auvrynt 1.0.2 → 1.0.5
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/LICENSE +21 -21
- package/README.md +366 -233
- package/addons/auvrynt_bridge/auvrynt_bridge.gd +500 -0
- package/addons/auvrynt_bridge/plugin.cfg +7 -0
- package/bin/auvrynt-launcher.cjs +77 -0
- package/dist/artifact-registry.js +1 -0
- package/dist/aseprite-tools.js +1 -0
- package/dist/auth/connection-registry.js +145 -0
- package/dist/auth/connection-status.js +176 -0
- package/dist/auth/oauth-provider.js +617 -0
- package/dist/auth/room-registry.js +131 -0
- package/dist/auth/session-registry.js +531 -0
- package/dist/background-lifecycle.js +1 -0
- package/dist/blender-client.js +1 -109
- package/dist/blender-tools.js +1 -930
- package/dist/browser-stability.js +1 -0
- package/dist/cli/commands/help-command.js +10 -0
- package/dist/cli/commands/init-command.js +190 -0
- package/dist/cli/commands/integration-commands.js +88 -0
- package/dist/cli/commands/serve-command.js +83 -0
- package/dist/cli/commands/setup-command.js +81 -0
- package/dist/cli/commands/status-commands.js +166 -0
- package/dist/cli/commands/tunnel-command.js +127 -0
- package/dist/cli/commands/user-config-commands.js +105 -0
- package/dist/cli/dashboard-actions.js +516 -0
- package/dist/cli/dashboard-native-actions.js +282 -0
- package/dist/cli/foreground-server.js +270 -0
- package/dist/cli/instance-control.js +21 -0
- package/dist/cli/instance-lock.js +123 -0
- package/dist/cli/integration-bootstrap.js +206 -0
- package/dist/cli/lifecycle-manager.js +493 -0
- package/dist/cli/runtime-support.js +74 -0
- package/dist/cli/serena-detected-default.js +27 -0
- package/dist/cli/tunnel-health-monitor.js +182 -0
- package/dist/cli.js +82 -739
- package/dist/config.js +1 -243
- package/dist/connection-registry.js +1 -73
- package/dist/connection-status.js +1 -139
- package/dist/control-retry.js +1 -0
- package/dist/crash-recovery.js +1 -0
- package/dist/db/client.js +16 -3
- package/dist/db/schema.js +30 -0
- package/dist/dotnet-tools.js +1 -223
- package/dist/git-worktrees.js +1 -134
- package/dist/git.js +1 -41
- package/dist/godot-animation-tilemap.js +1 -82
- package/dist/godot-csharp-build.js +1 -93
- package/dist/godot-csharp-project.js +1 -157
- package/dist/godot-csharp-runner.js +1 -146
- package/dist/godot-csharp-semantic.js +1 -161
- package/dist/godot-csharp-validate.js +1 -71
- package/dist/godot-dotnet-env.js +1 -169
- package/dist/godot-editor-bridge.js +1 -140
- package/dist/godot-gdscript.js +1 -824
- package/dist/godot-project-settings.js +1 -223
- package/dist/godot-runtime-testing.js +1 -249
- package/dist/godot-tools.js +1 -183
- package/dist/http-rate-limit.js +1 -0
- package/dist/http-server-hardening.js +1 -0
- package/dist/image-tools.js +1 -157
- package/dist/infrastructure/command-reference.js +32 -0
- package/dist/infrastructure/config.js +424 -0
- package/dist/infrastructure/context7-auth.js +55 -0
- package/dist/infrastructure/http-rate-limit.js +42 -0
- package/dist/infrastructure/http-server-hardening.js +23 -0
- package/dist/infrastructure/integration-queue.js +46 -0
- package/dist/infrastructure/logger.js +129 -0
- package/dist/infrastructure/mcp-event-store.js +103 -0
- package/dist/infrastructure/ngrok-auth-pool.js +208 -0
- package/dist/infrastructure/request-context.js +14 -0
- package/dist/infrastructure/shutdown.js +37 -0
- package/dist/infrastructure/sse-heartbeat.js +47 -0
- package/dist/infrastructure/tool-capabilities.js +67 -0
- package/dist/infrastructure/tool-result-budget.js +175 -0
- package/dist/infrastructure/user-config.js +167 -0
- package/dist/integration-discovery.js +1 -98
- package/dist/integration-queue.js +1 -0
- package/dist/integrations/agent-reach/agent-reach-tools.js +196 -0
- package/dist/integrations/agent-reach/native-channels.js +468 -0
- package/dist/integrations/aseprite/aseprite-analysis-tools.js +368 -0
- package/dist/integrations/aseprite/aseprite-editing-tools.js +647 -0
- package/dist/integrations/aseprite/aseprite-live-tools.js +297 -0
- package/dist/integrations/aseprite/aseprite-safety-tools.js +594 -0
- package/dist/integrations/aseprite/aseprite-specialized-tools.js +289 -0
- package/dist/integrations/aseprite/aseprite-tools.js +837 -0
- package/dist/integrations/blender/blender-catalog-mesh.js +593 -0
- package/dist/integrations/blender/blender-catalog-object.js +906 -0
- package/dist/integrations/blender/blender-catalog-scene.js +266 -0
- package/dist/integrations/blender/blender-catalog-select.js +581 -0
- package/dist/integrations/blender/blender-catalog-stubs.js +7512 -0
- package/dist/integrations/blender/blender-catalog.js +165 -0
- package/dist/integrations/blender/blender-client.js +105 -0
- package/dist/integrations/blender/blender-tools.js +2243 -0
- package/dist/integrations/context7/context7-tools.js +106 -0
- package/dist/integrations/dotnet/dotnet-tools.js +195 -0
- package/dist/integrations/godot/godot-animation-tilemap.js +74 -0
- package/dist/integrations/godot/godot-csharp-build.js +91 -0
- package/dist/integrations/godot/godot-csharp-project.js +155 -0
- package/dist/integrations/godot/godot-csharp-runner.js +118 -0
- package/dist/integrations/godot/godot-csharp-semantic.js +146 -0
- package/dist/integrations/godot/godot-csharp-validate.js +71 -0
- package/dist/integrations/godot/godot-dotnet-env.js +134 -0
- package/dist/integrations/godot/godot-editor-bridge.js +328 -0
- package/dist/integrations/godot/godot-gdscript.js +536 -0
- package/dist/integrations/godot/godot-project-settings.js +178 -0
- package/dist/integrations/godot/godot-runtime-testing.js +263 -0
- package/dist/integrations/godot/godot-tools.js +193 -0
- package/dist/integrations/images/image-tools.js +414 -0
- package/dist/integrations/images/png-codec.js +251 -0
- package/dist/integrations/images/view-image.js +99 -0
- package/dist/integrations/images/window-capture.js +148 -0
- package/dist/integrations/integration-discovery.js +185 -0
- package/dist/integrations/obsidian/obsidian-tools.js +205 -0
- package/dist/integrations/playwright/browser-session.js +516 -0
- package/dist/integrations/playwright/browser-stability.js +36 -0
- package/dist/integrations/playwright/playwright-runtime.js +105 -0
- package/dist/integrations/playwright/web-tools.js +504 -0
- package/dist/integrations/roblox/roblox-helpers.js +381 -0
- package/dist/integrations/roblox/roblox-studio-client.js +112 -0
- package/dist/integrations/roblox/roblox-tools.js +106 -0
- package/dist/integrations/serena/serena-manager.js +464 -0
- package/dist/integrations/serena/serena-tools.js +411 -0
- package/dist/logger.js +1 -76
- package/dist/mcp-event-store.js +1 -0
- package/dist/oauth-provider.js +1 -377
- package/dist/pi-tools.js +1 -81
- package/dist/playwright-runtime.js +1 -0
- package/dist/process/background-lifecycle.js +189 -0
- package/dist/process/control-retry.js +42 -0
- package/dist/process/crash-recovery.js +23 -0
- package/dist/process/processes.js +456 -0
- package/dist/processes.js +1 -218
- package/dist/request-context.js +1 -0
- package/dist/review-checkpoints.js +1 -142
- package/dist/room-registry.js +1 -0
- package/dist/roots.js +1 -53
- package/dist/search-discovery.js +1 -271
- package/dist/serena-manager.js +1 -443
- package/dist/serena-tools.js +1 -411
- package/dist/server/dashboard-page-styles.js +331 -0
- package/dist/server/dashboard-page.js +1509 -0
- package/dist/server/dashboard-routes.js +46 -0
- package/dist/server/dashboard.js +240 -0
- package/dist/server/http-helpers.js +30 -0
- package/dist/server/integration-profile-update.js +37 -0
- package/dist/server/mcp-policy.js +169 -0
- package/dist/server/mcp-server-factory.js +127 -0
- package/dist/server/mcp-tool-registrar.js +182 -0
- package/dist/server/openai-session-hint.js +14 -0
- package/dist/server/tool-groups.js +29 -0
- package/dist/server/tool-logging.js +33 -0
- package/dist/server/tool-registration-shared.js +59 -0
- package/dist/server/tools/aseprite-advanced-tools-registration.js +547 -0
- package/dist/server/tools/aseprite-tools-registration.js +213 -0
- package/dist/server/tools/blender-tools-registration.js +690 -0
- package/dist/server/tools/core-file-tools-registration.js +459 -0
- package/dist/server/tools/dotnet-godot-window-tools-registration.js +120 -0
- package/dist/server/tools/godot-csharp-tools-registration.js +252 -0
- package/dist/server/tools/godot-gdscript-tools-registration.js +189 -0
- package/dist/server/tools/process-project-tools-registration.js +155 -0
- package/dist/server/tools/roblox-tools-registration.js +514 -0
- package/dist/server/tools/web-image-tools-registration.js +326 -0
- package/dist/server/tools/workspace-lifecycle-tools-registration.js +130 -0
- package/dist/server/ui-assets.js +97 -0
- package/dist/server/workspace-analytics.js +92 -0
- package/dist/server.js +453 -2713
- package/dist/session-registry.js +1 -0
- package/dist/shutdown.js +1 -0
- package/dist/skills.js +1 -45
- package/dist/sse-heartbeat.js +1 -0
- package/dist/tool-capabilities.js +1 -0
- package/dist/tool-result-budget.js +1 -0
- package/dist/tools/pi-tools.js +81 -0
- package/dist/tunnels/cloudflare-tunnel.js +217 -0
- package/dist/tunnels/cloudflared-service.js +174 -0
- package/dist/tunnels/ngrok-tunnel.js +220 -0
- package/dist/tunnels/tunnel-manager.js +186 -0
- package/dist/tunnels/tunnel-types.js +1 -0
- package/dist/tunnels/tunnel-utils.js +62 -0
- package/dist/ui/.vite/manifest.json +9 -2487
- package/dist/ui/assets/heavy-payload-D42A9ceL.js +1 -0
- package/dist/ui/assets/lightweight-diff-Cv4g9Hdr.js +13 -0
- package/dist/ui/assets/review-payload-DKIg1cKF.js +1 -0
- package/dist/ui/assets/workspace-app-CeK3NhmB.css +1 -0
- package/dist/ui/assets/{workspace-app-C5QsE314.js → workspace-app-CkUXnpl4.js} +6 -6
- package/dist/ui/brand-theme.js +23 -0
- package/dist/ui/workspace-app.html +15 -15
- package/dist/user-config.js +1 -57
- package/dist/view-image.js +1 -104
- package/dist/web-tools.js +1 -200
- package/dist/window-capture.js +1 -74
- package/dist/workspace/artifact-registry.js +69 -0
- package/dist/workspace/git-worktrees.js +141 -0
- package/dist/workspace/git.js +42 -0
- package/dist/workspace/review-checkpoints.js +142 -0
- package/dist/workspace/roots.js +56 -0
- package/dist/workspace/search-discovery.js +264 -0
- package/dist/workspace/skills.js +45 -0
- package/dist/workspace/workspace-store.js +219 -0
- package/dist/workspace/workspaces.js +314 -0
- package/dist/workspace-store.js +1 -125
- package/dist/workspaces.js +1 -226
- package/docs/CREATOR_STORE_FREE_ASSETS.md +162 -0
- package/docs/DEVELOPMENT_TOOLS.md +136 -93
- package/docs/assets/auvrynt-icon.png +0 -0
- package/docs/assets/auvrynt-icon.svg +20 -0
- package/docs/chatgpt-coding-workflow.md +143 -143
- package/docs/configuration.md +156 -124
- package/docs/diagnostics.md +79 -0
- package/docs/gotchas.md +244 -202
- package/docs/multi-agent-and-long-projects.md +91 -0
- package/docs/security.md +138 -100
- package/docs/setup.md +171 -131
- package/docs/source-layout.md +60 -0
- package/extensions/auvrynt_bridge/auvrynt_bridge.lua +594 -0
- package/extensions/auvrynt_bridge/live_analysis.lua +181 -0
- package/extensions/auvrynt_bridge/live_animation.lua +134 -0
- package/extensions/auvrynt_bridge/live_commands.lua +24 -0
- package/extensions/auvrynt_bridge/live_common.lua +130 -0
- package/extensions/auvrynt_bridge/live_document.lua +78 -0
- package/extensions/auvrynt_bridge/live_drawing.lua +125 -0
- package/extensions/auvrynt_bridge/live_effects.lua +91 -0
- package/extensions/auvrynt_bridge/live_palette_template.lua +167 -0
- package/extensions/auvrynt_bridge/live_selection.lua +110 -0
- package/extensions/auvrynt_bridge/live_structure.lua +129 -0
- package/extensions/auvrynt_bridge/package.json +17 -0
- package/guides/ASEPRITE_AGENT_GUIDE.md +133 -0
- package/guides/BLENDER_AGENT_GUIDE.md +472 -0
- package/guides/GODOT_AGENT_GUIDE.md +298 -0
- package/guides/PROJECT_ROUTER.md +165 -0
- package/guides/ROBLOX_AGENT_GUIDE.md +75 -0
- package/guides/SOFTWARE_AGENT_GUIDE.md +104 -0
- package/guides/WEB_AGENT_GUIDE.md +287 -0
- package/package.json +78 -70
- package/scripts/dev-server.mjs +121 -120
- package/scripts/live-tunnel-smoke.mjs +538 -0
- package/scripts/repo-hygiene.mjs +74 -0
- package/scripts/restart-after-crash.mjs +49 -0
- package/scripts/run-tests.mjs +166 -0
- package/dist/ui/assets/abap-CLvhMVsD.js +0 -1
- package/dist/ui/assets/actionscript-3--17pq3dv.js +0 -1
- package/dist/ui/assets/ada-C5qYipkI.js +0 -1
- package/dist/ui/assets/andromeeda-vGVdxbeo.js +0 -1
- package/dist/ui/assets/angular-html-BJqQFYI6.js +0 -1
- package/dist/ui/assets/angular-ts-CMJECO0Y.js +0 -1
- package/dist/ui/assets/apache-U0d_L8uA.js +0 -1
- package/dist/ui/assets/apex-CGTLDQj6.js +0 -1
- package/dist/ui/assets/apl-DWeXpBBr.js +0 -1
- package/dist/ui/assets/applescript-CCn79oCD.js +0 -1
- package/dist/ui/assets/ara-4CJ0cIlV.js +0 -1
- package/dist/ui/assets/asciidoc-DE70LPWp.js +0 -1
- package/dist/ui/assets/asm-Cmm7eHzH.js +0 -1
- package/dist/ui/assets/astro-CLbttLOq.js +0 -1
- package/dist/ui/assets/aurora-x-CDeNXAV0.js +0 -1
- package/dist/ui/assets/awk-BWXHIvNe.js +0 -1
- package/dist/ui/assets/ayu-dark-DluEY0Gj.js +0 -1
- package/dist/ui/assets/ayu-light-C3h-C4tm.js +0 -1
- package/dist/ui/assets/ayu-mirage-Bqwy1Gya.js +0 -1
- package/dist/ui/assets/ballerina-B7ZEbQpA.js +0 -1
- package/dist/ui/assets/bat-Bo4NYOV-.js +0 -1
- package/dist/ui/assets/beancount-D-usSTwE.js +0 -1
- package/dist/ui/assets/berry-DKpUyyne.js +0 -1
- package/dist/ui/assets/bibtex-Ci_nEsc7.js +0 -1
- package/dist/ui/assets/bicep-CUHmPFLl.js +0 -1
- package/dist/ui/assets/bird2-C2hNVINV.js +0 -1
- package/dist/ui/assets/blade-BOzY0P2V.js +0 -1
- package/dist/ui/assets/bsl-BkkzgIyY.js +0 -1
- package/dist/ui/assets/c-BG-8uJvh.js +0 -1
- package/dist/ui/assets/c3-CnJL0r0V.js +0 -1
- package/dist/ui/assets/cadence-CQ2zXKGN.js +0 -1
- package/dist/ui/assets/cairo-DLTphjLi.js +0 -1
- package/dist/ui/assets/catppuccin-frappe-3VR1Za6u.js +0 -1
- package/dist/ui/assets/catppuccin-latte-DwIHMF0Q.js +0 -1
- package/dist/ui/assets/catppuccin-macchiato-DYnBP6_5.js +0 -1
- package/dist/ui/assets/catppuccin-mocha-DYhrFGRu.js +0 -1
- package/dist/ui/assets/clarity-SemFz856.js +0 -1
- package/dist/ui/assets/clojure-DqKBuwfJ.js +0 -1
- package/dist/ui/assets/cmake-Bj61d0ZC.js +0 -1
- package/dist/ui/assets/cobol-I_17IuGe.js +0 -1
- package/dist/ui/assets/codeowners-C8r90Shi.js +0 -1
- package/dist/ui/assets/codeql-oeQT6MSM.js +0 -1
- package/dist/ui/assets/coffee-C0B8hmok.js +0 -1
- package/dist/ui/assets/common-lisp-Cv5bFMCO.js +0 -1
- package/dist/ui/assets/coq-BrsZFFmf.js +0 -1
- package/dist/ui/assets/cpp-DDJXt6Vs.js +0 -1
- package/dist/ui/assets/crystal-Bexqace6.js +0 -1
- package/dist/ui/assets/csharp-Ct8U2NOr.js +0 -1
- package/dist/ui/assets/css-DSQhw_9R.js +0 -1
- package/dist/ui/assets/csv-Dx-8-gkx.js +0 -1
- package/dist/ui/assets/cue-CE9AQfxI.js +0 -1
- package/dist/ui/assets/cypher-ClKdZ_lG.js +0 -1
- package/dist/ui/assets/d-qD-0Kul2.js +0 -1
- package/dist/ui/assets/dark-plus-Cs2F2srj.js +0 -1
- package/dist/ui/assets/dart-DkHntEIa.js +0 -1
- package/dist/ui/assets/dax-BkyTk9wS.js +0 -1
- package/dist/ui/assets/desktop-Dlh5hvp9.js +0 -1
- package/dist/ui/assets/diff-woXpYk--.js +0 -1
- package/dist/ui/assets/docker-IyjqRm3v.js +0 -1
- package/dist/ui/assets/dotenv-_5a1GRtc.js +0 -1
- package/dist/ui/assets/dracula-BHWKrbxM.js +0 -1
- package/dist/ui/assets/dracula-soft-5eyTD99u.js +0 -1
- package/dist/ui/assets/dream-maker-DW3nJb8Q.js +0 -1
- package/dist/ui/assets/edge-Z8YYkHOr.js +0 -1
- package/dist/ui/assets/elixir-CG9uKtAF.js +0 -1
- package/dist/ui/assets/elm-GfWG2IfT.js +0 -1
- package/dist/ui/assets/emacs-lisp-C9PiwqqW.js +0 -1
- package/dist/ui/assets/erb-xe89e73J.js +0 -1
- package/dist/ui/assets/erlang-Cphh6RMH.js +0 -1
- package/dist/ui/assets/everforest-dark-sB-x3p7T.js +0 -1
- package/dist/ui/assets/everforest-light-Df2xbC6M.js +0 -1
- package/dist/ui/assets/fennel-DQxkIbk2.js +0 -1
- package/dist/ui/assets/fish-BJitypiv.js +0 -1
- package/dist/ui/assets/fluent-C03EYrpw.js +0 -1
- package/dist/ui/assets/fortran-fixed-form-DEKoE2YW.js +0 -1
- package/dist/ui/assets/fortran-free-form-CYNrtFtB.js +0 -1
- package/dist/ui/assets/fsharp-D13ZGOAj.js +0 -1
- package/dist/ui/assets/gdresource-C0sCabJj.js +0 -1
- package/dist/ui/assets/gdscript-Cp2uCuqX.js +0 -1
- package/dist/ui/assets/gdshader-CBce3t8t.js +0 -1
- package/dist/ui/assets/genie-CV2tkWYe.js +0 -1
- package/dist/ui/assets/gherkin-DExj1W_8.js +0 -1
- package/dist/ui/assets/git-commit-BSykSTBG.js +0 -1
- package/dist/ui/assets/git-rebase-CoTL_uSE.js +0 -1
- package/dist/ui/assets/github-dark-C-LZuMrd.js +0 -1
- package/dist/ui/assets/github-dark-default-DXG-b-1a.js +0 -1
- package/dist/ui/assets/github-dark-dimmed-Bx1FflLF.js +0 -1
- package/dist/ui/assets/github-dark-high-contrast-B_tTalzw.js +0 -1
- package/dist/ui/assets/github-light-EUqPIrTm.js +0 -1
- package/dist/ui/assets/github-light-default-BXViO-2h.js +0 -1
- package/dist/ui/assets/github-light-high-contrast-B68TUdTA.js +0 -1
- package/dist/ui/assets/gleam-CSRkHgEL.js +0 -1
- package/dist/ui/assets/glimmer-js-DAn4UCSu.js +0 -1
- package/dist/ui/assets/glimmer-ts-Tjyi6Gh5.js +0 -1
- package/dist/ui/assets/glsl-CtTDZoqR.js +0 -1
- package/dist/ui/assets/gn-ilITqXS6.js +0 -1
- package/dist/ui/assets/gnuplot-7GGW24-e.js +0 -1
- package/dist/ui/assets/go-BJwz_mda.js +0 -1
- package/dist/ui/assets/graphql-D5gcC_Jk.js +0 -1
- package/dist/ui/assets/groovy-CacY0gHj.js +0 -1
- package/dist/ui/assets/gruvbox-dark-hard-C820rvS2.js +0 -1
- package/dist/ui/assets/gruvbox-dark-medium-BPjhmG05.js +0 -1
- package/dist/ui/assets/gruvbox-dark-soft-MrdJrrXF.js +0 -1
- package/dist/ui/assets/gruvbox-light-hard-BC_s9l72.js +0 -1
- package/dist/ui/assets/gruvbox-light-medium-BAWPOn9u.js +0 -1
- package/dist/ui/assets/gruvbox-light-soft-BSMLrYjP.js +0 -1
- package/dist/ui/assets/hack-BJXY27dt.js +0 -1
- package/dist/ui/assets/haml-BLfFoZf7.js +0 -1
- package/dist/ui/assets/handlebars-Dw6CWkvN.js +0 -1
- package/dist/ui/assets/haskell-D8IpX4py.js +0 -1
- package/dist/ui/assets/haxe-OTjmBuCE.js +0 -1
- package/dist/ui/assets/hcl-Dh228itO.js +0 -1
- package/dist/ui/assets/heavy-payload-Dcg0-F-S.js +0 -4
- package/dist/ui/assets/hjson-CxZEssPk.js +0 -1
- package/dist/ui/assets/hlsl-Cvrh5tZx.js +0 -1
- package/dist/ui/assets/horizon-CE9ld1lL.js +0 -1
- package/dist/ui/assets/horizon-bright-Br1oVSNq.js +0 -1
- package/dist/ui/assets/houston-CsvMBhTu.js +0 -1
- package/dist/ui/assets/html-CAcAWvoN.js +0 -1
- package/dist/ui/assets/html-derivative-8aSW2E_7.js +0 -1
- package/dist/ui/assets/http-B2YR_3V1.js +0 -1
- package/dist/ui/assets/hurl-BnDJ9Zhf.js +0 -1
- package/dist/ui/assets/hxml-B0Qn7Nwc.js +0 -1
- package/dist/ui/assets/hy-CZbG8q4J.js +0 -1
- package/dist/ui/assets/imba-DsUTQ-LC.js +0 -1
- package/dist/ui/assets/ini-B5eOa1yu.js +0 -1
- package/dist/ui/assets/java-Doxi4W8u.js +0 -1
- package/dist/ui/assets/javascript-BbRdEqti.js +0 -1
- package/dist/ui/assets/jinja-CS3Tpv_Q.js +0 -1
- package/dist/ui/assets/jison-BkPGYVHR.js +0 -1
- package/dist/ui/assets/json-BMt1m3m8.js +0 -1
- package/dist/ui/assets/json5-BR5RXkoi.js +0 -1
- package/dist/ui/assets/jsonc-CYpm1nAK.js +0 -1
- package/dist/ui/assets/jsonl-CmCQp5Yx.js +0 -1
- package/dist/ui/assets/jsonnet-CJTPZ8u_.js +0 -1
- package/dist/ui/assets/jssm-DXw9l8Rf.js +0 -1
- package/dist/ui/assets/jsx-CQKrJXXY.js +0 -1
- package/dist/ui/assets/julia-BuN7i2du.js +0 -1
- package/dist/ui/assets/just-BswEPFPu.js +0 -1
- package/dist/ui/assets/kanagawa-dragon-CXtmUGW6.js +0 -1
- package/dist/ui/assets/kanagawa-lotus-BN08jTvb.js +0 -1
- package/dist/ui/assets/kanagawa-wave-CTweb8Dz.js +0 -1
- package/dist/ui/assets/kdl-CsD5j6eV.js +0 -1
- package/dist/ui/assets/kotlin-DhhofPvG.js +0 -1
- package/dist/ui/assets/kusto-BUv0MjJC.js +0 -1
- package/dist/ui/assets/laserwave-C_8bwKvT.js +0 -1
- package/dist/ui/assets/latex-DU2VyFfA.js +0 -1
- package/dist/ui/assets/lean-CewbzKMR.js +0 -1
- package/dist/ui/assets/less-DVTAwKKz.js +0 -1
- package/dist/ui/assets/light-plus-DVQuIRkW.js +0 -1
- package/dist/ui/assets/liquid-Cmz1L3dq.js +0 -1
- package/dist/ui/assets/llvm-Cm23YOpf.js +0 -1
- package/dist/ui/assets/log-BNLmms1o.js +0 -1
- package/dist/ui/assets/logo-Cluzi2Zq.js +0 -1
- package/dist/ui/assets/lua-CfVXhkaJ.js +0 -1
- package/dist/ui/assets/luau-CNKltnaQ.js +0 -1
- package/dist/ui/assets/make-Dixweg8N.js +0 -1
- package/dist/ui/assets/markdown-BYOwaDjH.js +0 -1
- package/dist/ui/assets/marko-C5bfqGiA.js +0 -1
- package/dist/ui/assets/material-theme-Bm3Qr25_.js +0 -1
- package/dist/ui/assets/material-theme-darker-2IIEA8gg.js +0 -1
- package/dist/ui/assets/material-theme-lighter-uhdI0v04.js +0 -1
- package/dist/ui/assets/material-theme-ocean-CHQ94UKr.js +0 -1
- package/dist/ui/assets/material-theme-palenight-B5W6OYN7.js +0 -1
- package/dist/ui/assets/matlab-D7qyCx1q.js +0 -1
- package/dist/ui/assets/mdc-CVBXYfyq.js +0 -1
- package/dist/ui/assets/mdx-DQZ5AkYe.js +0 -1
- package/dist/ui/assets/mermaid-Bk4SNUv9.js +0 -1
- package/dist/ui/assets/min-dark-BSWPekZh.js +0 -1
- package/dist/ui/assets/min-light-DDpmG2fV.js +0 -1
- package/dist/ui/assets/mipsasm-BMqwQI7S.js +0 -1
- package/dist/ui/assets/mojo-BgCJLMeH.js +0 -1
- package/dist/ui/assets/monokai-CdkpiU2Y.js +0 -1
- package/dist/ui/assets/moonbit-CaWjb8XO.js +0 -1
- package/dist/ui/assets/move-B1IS1UjX.js +0 -1
- package/dist/ui/assets/narrat-_X_XdTYD.js +0 -1
- package/dist/ui/assets/nextflow-Bbiyy34d.js +0 -1
- package/dist/ui/assets/nextflow-groovy-Dc_ddanL.js +0 -1
- package/dist/ui/assets/nginx-CzJafxLa.js +0 -1
- package/dist/ui/assets/night-owl-DhmEMT88.js +0 -1
- package/dist/ui/assets/night-owl-light-eJ-hLW7d.js +0 -1
- package/dist/ui/assets/nim-DABKtHtM.js +0 -1
- package/dist/ui/assets/nix-IvuFDN5E.js +0 -1
- package/dist/ui/assets/nord-Cb4Vim4T.js +0 -1
- package/dist/ui/assets/nushell-DcLAeLz5.js +0 -1
- package/dist/ui/assets/objective-c-D1A_Heim.js +0 -1
- package/dist/ui/assets/objective-cpp-BsSzOQcm.js +0 -1
- package/dist/ui/assets/ocaml-O90oeIOV.js +0 -1
- package/dist/ui/assets/odin-B1RWQWA5.js +0 -1
- package/dist/ui/assets/one-dark-pro-CLwyXe_n.js +0 -1
- package/dist/ui/assets/one-light-D7Lr4KcI.js +0 -1
- package/dist/ui/assets/openscad-BUDT5pXO.js +0 -1
- package/dist/ui/assets/pascal-4ZHwLPI5.js +0 -1
- package/dist/ui/assets/perl-CBh7L3lZ.js +0 -1
- package/dist/ui/assets/php-DFbI9q5p.js +0 -1
- package/dist/ui/assets/pierre-dark-sU4Zdns8.js +0 -1
- package/dist/ui/assets/pierre-dark-soft-HXgun5vs.js +0 -1
- package/dist/ui/assets/pierre-light-DWBk51d8.js +0 -1
- package/dist/ui/assets/pierre-light-soft-CodEzPxf.js +0 -1
- package/dist/ui/assets/pkl-ot-7Btpt.js +0 -1
- package/dist/ui/assets/plastic-DQwYfKfQ.js +0 -1
- package/dist/ui/assets/plsql-DGHpHOYJ.js +0 -1
- package/dist/ui/assets/po-BiJDBrnU.js +0 -1
- package/dist/ui/assets/poimandres-DRFjx7u4.js +0 -1
- package/dist/ui/assets/polar-C7UOKdEL.js +0 -1
- package/dist/ui/assets/postcss-BXeXVLqQ.js +0 -1
- package/dist/ui/assets/powerquery-DNMTfnFr.js +0 -1
- package/dist/ui/assets/powershell-DshXNtvi.js +0 -1
- package/dist/ui/assets/prisma-BsRQq5mF.js +0 -1
- package/dist/ui/assets/prolog-iXnhIJG7.js +0 -1
- package/dist/ui/assets/proto-DB4EqR-F.js +0 -1
- package/dist/ui/assets/pug-C_PxC7gO.js +0 -1
- package/dist/ui/assets/puppet-CDv2pdJW.js +0 -1
- package/dist/ui/assets/purescript-9MfHhQsQ.js +0 -1
- package/dist/ui/assets/python-gzcpVVnB.js +0 -1
- package/dist/ui/assets/qml-DtngoFFK.js +0 -1
- package/dist/ui/assets/qmldir-DCQb3MpD.js +0 -1
- package/dist/ui/assets/qss-Fe1Jh2GI.js +0 -1
- package/dist/ui/assets/r-DohkcevW.js +0 -1
- package/dist/ui/assets/racket-DcIDlBhZ.js +0 -1
- package/dist/ui/assets/raku-B3gFvitq.js +0 -1
- package/dist/ui/assets/razor-C4t8J0_E.js +0 -1
- package/dist/ui/assets/red-CJ3rzSJv.js +0 -1
- package/dist/ui/assets/reg-CRGYupPL.js +0 -1
- package/dist/ui/assets/regexp-OGbTbjgY.js +0 -1
- package/dist/ui/assets/rel-BtDbiS_P.js +0 -1
- package/dist/ui/assets/review-payload-C5Qz60Kq.js +0 -1
- package/dist/ui/assets/riscv-Ckw8ddFX.js +0 -1
- package/dist/ui/assets/ron-VUp2lXgN.js +0 -1
- package/dist/ui/assets/rose-pine-BthvhNj6.js +0 -1
- package/dist/ui/assets/rose-pine-dawn-Dg85fqjY.js +0 -1
- package/dist/ui/assets/rose-pine-moon-hon4tzzS.js +0 -1
- package/dist/ui/assets/rosmsg-CAekHB0j.js +0 -1
- package/dist/ui/assets/rst-CfBbbcvC.js +0 -1
- package/dist/ui/assets/ruby-Bw0mpxHY.js +0 -1
- package/dist/ui/assets/rust-Cfkwpbl8.js +0 -1
- package/dist/ui/assets/sas-Cs3s9JOf.js +0 -1
- package/dist/ui/assets/sass-DXrisJhu.js +0 -1
- package/dist/ui/assets/scala-DKOlJaKm.js +0 -1
- package/dist/ui/assets/scheme-DQCgrYNe.js +0 -1
- package/dist/ui/assets/scss-sRxNJS54.js +0 -1
- package/dist/ui/assets/sdbl-bTVj8UrX.js +0 -1
- package/dist/ui/assets/shaderlab-TOUzSsQk.js +0 -1
- package/dist/ui/assets/shellscript-B0X6wh0R.js +0 -1
- package/dist/ui/assets/shellsession-D2FdOioR.js +0 -1
- package/dist/ui/assets/slack-dark-DnToyrRv.js +0 -1
- package/dist/ui/assets/slack-ochin-B2OO5cIa.js +0 -1
- package/dist/ui/assets/smalltalk-B16xEiuN.js +0 -1
- package/dist/ui/assets/snazzy-light-4G7pJPwS.js +0 -1
- package/dist/ui/assets/solarized-dark-DV17i1UV.js +0 -1
- package/dist/ui/assets/solarized-light-DSh2HLQt.js +0 -1
- package/dist/ui/assets/solidity-CKzVLygQ.js +0 -1
- package/dist/ui/assets/soy-s6g9OjJ1.js +0 -1
- package/dist/ui/assets/sparql-D_iOobhT.js +0 -1
- package/dist/ui/assets/splunk-BC2Px7Mm.js +0 -1
- package/dist/ui/assets/sql-DVTnh5V-.js +0 -1
- package/dist/ui/assets/ssh-config-BgfXC-Er.js +0 -1
- package/dist/ui/assets/stata-DFIDiXF9.js +0 -1
- package/dist/ui/assets/stylus-B6D30XZt.js +0 -1
- package/dist/ui/assets/surrealql-DVfrsLyg.js +0 -1
- package/dist/ui/assets/svelte-D5GsxESq.js +0 -1
- package/dist/ui/assets/swift-DonLKvLd.js +0 -1
- package/dist/ui/assets/synthwave-84-nFMaYfgc.js +0 -1
- package/dist/ui/assets/system-verilog-DJ5XKQeo.js +0 -1
- package/dist/ui/assets/systemd-BxMlprV5.js +0 -1
- package/dist/ui/assets/talonscript-CohzipZa.js +0 -1
- package/dist/ui/assets/tasl-DMoTqEGO.js +0 -1
- package/dist/ui/assets/tcl-CZd0xW_V.js +0 -1
- package/dist/ui/assets/templ-DI-Zyqzd.js +0 -1
- package/dist/ui/assets/terraform-DswuEJGm.js +0 -1
- package/dist/ui/assets/tex-WHHmlbJI.js +0 -1
- package/dist/ui/assets/tokyo-night-oM2G3aXe.js +0 -1
- package/dist/ui/assets/toml-CcmNWLt0.js +0 -1
- package/dist/ui/assets/ts-tags-Dwpo2RFJ.js +0 -1
- package/dist/ui/assets/tsv-sltzmVWM.js +0 -1
- package/dist/ui/assets/tsx-ph_idaAW.js +0 -1
- package/dist/ui/assets/turtle-ByJddavk.js +0 -1
- package/dist/ui/assets/twig-YO17jFjR.js +0 -1
- package/dist/ui/assets/typescript-CbAxjhkl.js +0 -1
- package/dist/ui/assets/typespec-B88KGewJ.js +0 -1
- package/dist/ui/assets/typst-DI99ib-x.js +0 -1
- package/dist/ui/assets/useFileDiffInstance-B2DLX3Vg.js +0 -244
- package/dist/ui/assets/v-DETTlOr0.js +0 -1
- package/dist/ui/assets/vala-zf12oZj6.js +0 -1
- package/dist/ui/assets/vb-Djn5o6TS.js +0 -1
- package/dist/ui/assets/verilog-CiiDBU1e.js +0 -1
- package/dist/ui/assets/vesper-D5bVUKB1.js +0 -1
- package/dist/ui/assets/vhdl-BroJfC0k.js +0 -1
- package/dist/ui/assets/viml-DvXPmvsu.js +0 -1
- package/dist/ui/assets/vitesse-black-fwtXNY1n.js +0 -1
- package/dist/ui/assets/vitesse-dark-BZCL-v6S.js +0 -1
- package/dist/ui/assets/vitesse-light-VbXTXTou.js +0 -1
- package/dist/ui/assets/vue-CraHL-Ps.js +0 -1
- package/dist/ui/assets/vue-html-e9tyZNtS.js +0 -1
- package/dist/ui/assets/vue-vine-CofmxaUb.js +0 -1
- package/dist/ui/assets/vyper-CgoNMtux.js +0 -1
- package/dist/ui/assets/wasm-BnjxR4X6.js +0 -1
- package/dist/ui/assets/wasm-ByWQv1Qj.js +0 -1
- package/dist/ui/assets/wenyan-C8pVoKbM.js +0 -1
- package/dist/ui/assets/wgsl-BsKzXJz4.js +0 -1
- package/dist/ui/assets/wikitext-ClFFjSW2.js +0 -1
- package/dist/ui/assets/wit-DdvCle-K.js +0 -1
- package/dist/ui/assets/wolfram-DLL8P-h_.js +0 -1
- package/dist/ui/assets/workspace-app-8--oTbCd.css +0 -1
- package/dist/ui/assets/xml-BWSdPZHm.js +0 -1
- package/dist/ui/assets/xsl-BtCt7Hx8.js +0 -1
- package/dist/ui/assets/yaml-BZiTw7cQ.js +0 -1
- package/dist/ui/assets/zenscript-BnlCZFoB.js +0 -1
- package/dist/ui/assets/zig-CMLA9XwU.js +0 -1
- package/docs/assets/auvrynt-logo-light.png +0 -0
- package/docs/assets/auvrynt-screenshot.png +0 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { assertInteger, assertPositiveInteger, errorResponse, getAsepritePalettePreset, luaString, openSpriteScript, parseColor, resolveAsepriteExecutable, runLua, textResponse, workspacePath, } from "./aseprite-tools.js";
|
|
6
|
+
import { asepriteFileSafety, assertAsepriteExpectedVersion, } from "./aseprite-safety-tools.js";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
8
|
+
const MAX_MASK_POINTS = 262_144;
|
|
9
|
+
const MAX_STROKE_POINTS = 16_384;
|
|
10
|
+
async function prepareMutation(config, registry, workspaceId, filePath, guard, label) {
|
|
11
|
+
await assertAsepriteExpectedVersion(registry, workspaceId, filePath, guard.expectedVersion);
|
|
12
|
+
if (guard.checkpoint !== false) {
|
|
13
|
+
const response = await asepriteFileSafety(config, registry, {
|
|
14
|
+
workspaceId,
|
|
15
|
+
filePath,
|
|
16
|
+
action: "checkpoint",
|
|
17
|
+
expectedVersion: guard.expectedVersion,
|
|
18
|
+
label,
|
|
19
|
+
});
|
|
20
|
+
if (response.isError) {
|
|
21
|
+
const message = response.content[0]?.type === "text" ? response.content[0].text : "Checkpoint failed.";
|
|
22
|
+
throw new Error(message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function luaColor(value) {
|
|
27
|
+
const color = parseColor(value);
|
|
28
|
+
return `{r=${color.r},g=${color.g},b=${color.b},a=${color.a}}`;
|
|
29
|
+
}
|
|
30
|
+
function normalizeRegion(region) {
|
|
31
|
+
return {
|
|
32
|
+
x: assertInteger(region.x, "region.x"),
|
|
33
|
+
y: assertInteger(region.y, "region.y"),
|
|
34
|
+
width: assertPositiveInteger(region.width, "region.width"),
|
|
35
|
+
height: assertPositiveInteger(region.height, "region.height"),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export async function asepriteImportSpriteSheet(config, registry, input) {
|
|
39
|
+
try {
|
|
40
|
+
const source = workspacePath(registry, input.workspaceId, input.imagePath);
|
|
41
|
+
const output = workspacePath(registry, input.workspaceId, input.outputPath);
|
|
42
|
+
await mkdir(dirname(output.absolute), { recursive: true });
|
|
43
|
+
const frameWidth = assertPositiveInteger(input.frameWidth, "frameWidth");
|
|
44
|
+
const frameHeight = assertPositiveInteger(input.frameHeight, "frameHeight");
|
|
45
|
+
const marginX = Math.max(0, assertInteger(input.marginX ?? 0, "marginX"));
|
|
46
|
+
const marginY = Math.max(0, assertInteger(input.marginY ?? 0, "marginY"));
|
|
47
|
+
const spacingX = Math.max(0, assertInteger(input.spacingX ?? 0, "spacingX"));
|
|
48
|
+
const spacingY = Math.max(0, assertInteger(input.spacingY ?? 0, "spacingY"));
|
|
49
|
+
const durationMs = Math.max(1, Math.min(60_000, assertInteger(input.durationMs ?? 100, "durationMs")));
|
|
50
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
51
|
+
local source=app.open(${luaString(source.absolute)})
|
|
52
|
+
if source==nil then fail("Unable to open sprite sheet") end
|
|
53
|
+
local rendered=Image(source.spec) rendered:clear() rendered:drawSprite(source,1,Point(0,0))
|
|
54
|
+
local frame_width=${frameWidth} local frame_height=${frameHeight}
|
|
55
|
+
local margin_x=${marginX} local margin_y=${marginY} local spacing_x=${spacingX} local spacing_y=${spacingY}
|
|
56
|
+
local columns=${input.columns ?? "math.floor((source.width-margin_x+spacing_x)/(frame_width+spacing_x))"}
|
|
57
|
+
local rows=${input.rows ?? "math.floor((source.height-margin_y+spacing_y)/(frame_height+spacing_y))"}
|
|
58
|
+
if columns<1 or rows<1 then fail("Frame grid does not fit the source image") end
|
|
59
|
+
local count=${input.frameCount ?? "columns*rows"}
|
|
60
|
+
if count<1 or count>columns*rows then fail("frameCount is outside the available grid") end
|
|
61
|
+
local sprite=Sprite(frame_width,frame_height,source.colorMode)
|
|
62
|
+
if #source.palettes>0 then sprite:setPalette(source.palettes[1]) end
|
|
63
|
+
sprite.transparentColor=source.transparentColor
|
|
64
|
+
local layer=sprite.layers[1] layer.name=${luaString(input.layerName?.trim() || "Imported")}
|
|
65
|
+
for index=0,count-1 do
|
|
66
|
+
local column local row
|
|
67
|
+
if ${luaString(input.order ?? "row_major")}=="column_major" then column=math.floor(index/rows) row=index%rows
|
|
68
|
+
else row=math.floor(index/columns) column=index%columns end
|
|
69
|
+
local sx=margin_x+column*(frame_width+spacing_x)
|
|
70
|
+
local sy=margin_y+row*(frame_height+spacing_y)
|
|
71
|
+
if sx+frame_width>source.width or sy+frame_height>source.height then fail("Frame rectangle exceeds source image") end
|
|
72
|
+
local image=Image(sprite.spec) image:clear() image:drawImage(rendered,Point(-sx,-sy))
|
|
73
|
+
local frame_number=index+1
|
|
74
|
+
if frame_number==1 then
|
|
75
|
+
layer:cel(1).image=image
|
|
76
|
+
else
|
|
77
|
+
sprite:newEmptyFrame(frame_number)
|
|
78
|
+
sprite:newCel(layer,frame_number,image,Point(0,0))
|
|
79
|
+
end
|
|
80
|
+
sprite.frames[frame_number].duration=${durationMs / 1000}
|
|
81
|
+
end
|
|
82
|
+
${input.tagName ? `local tag=sprite:newTag(1,count) tag.name=${luaString(input.tagName)}` : ""}
|
|
83
|
+
if not sprite:saveAs(${luaString(output.absolute)}) then fail("Unable to save imported sprite") end
|
|
84
|
+
emit_result({source=${luaString(source.relative)},output=${luaString(output.relative)},frames=count,columns=columns,rows=rows,summary=sprite_summary(sprite)})
|
|
85
|
+
sprite:close() source:close()
|
|
86
|
+
`);
|
|
87
|
+
return textResponse(result);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export async function asepriteEditRegion(config, registry, input) {
|
|
94
|
+
try {
|
|
95
|
+
await prepareMutation(config, registry, input.workspaceId, input.targetPath, input, "edit-region");
|
|
96
|
+
const target = workspacePath(registry, input.workspaceId, input.targetPath);
|
|
97
|
+
const source = workspacePath(registry, input.workspaceId, input.sourcePath ?? input.targetPath);
|
|
98
|
+
const region = normalizeRegion(input.sourceRegion);
|
|
99
|
+
const sourceFrame = assertPositiveInteger(input.sourceFrame ?? 1, "sourceFrame");
|
|
100
|
+
const targetFrame = assertPositiveInteger(input.targetFrame ?? 1, "targetFrame");
|
|
101
|
+
const targetX = assertInteger(input.targetX, "targetX");
|
|
102
|
+
const targetY = assertInteger(input.targetY, "targetY");
|
|
103
|
+
const scale = Math.min(16, assertPositiveInteger(input.scale ?? 1, "scale"));
|
|
104
|
+
const rotation = input.rotation ?? 0;
|
|
105
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
106
|
+
local target=app.open(${luaString(target.absolute)})
|
|
107
|
+
if target==nil then fail("Unable to open target sprite") end
|
|
108
|
+
local source=${source.absolute === target.absolute ? "target" : `app.open(${luaString(source.absolute)})`}
|
|
109
|
+
if source==nil then fail("Unable to open source sprite") end
|
|
110
|
+
if ${sourceFrame}>#source.frames or ${targetFrame}>#target.frames then fail("Frame is outside a sprite") end
|
|
111
|
+
local source_image=Image(source.spec) source_image:clear()
|
|
112
|
+
${input.sourceLayer ? `
|
|
113
|
+
local source_layer=find_layer(source.layers,${luaString(input.sourceLayer)})
|
|
114
|
+
if source_layer==nil or source_layer.isGroup then fail("Source layer was not found") end
|
|
115
|
+
local source_cel=source_layer:cel(${sourceFrame})
|
|
116
|
+
if source_cel~=nil then source_image:drawImage(source_cel.image,source_cel.position) end
|
|
117
|
+
` : `source_image:drawSprite(source,${sourceFrame},Point(0,0))`}
|
|
118
|
+
if ${region.x}<0 or ${region.y}<0 or ${region.x + region.width}>source.width or ${region.y + region.height}>source.height then fail("Source region is outside the sprite") end
|
|
119
|
+
local rotation=${rotation}
|
|
120
|
+
local scaled_width=${region.width * scale} local scaled_height=${region.height * scale}
|
|
121
|
+
local output_width=(rotation==90 or rotation==270) and scaled_height or scaled_width
|
|
122
|
+
local output_height=(rotation==90 or rotation==270) and scaled_width or scaled_height
|
|
123
|
+
local target_layer=${input.targetLayer ? `find_layer(target.layers,${luaString(input.targetLayer)})` : "target.layers[1]"}
|
|
124
|
+
if target_layer==nil and ${input.createTargetLayer === true ? "true" : "false"} then target_layer=target:newLayer() target_layer.name=${luaString(input.targetLayer ?? "Region")} end
|
|
125
|
+
if target_layer==nil or target_layer.isGroup then fail("Target layer was not found") end
|
|
126
|
+
local target_cel=ensure_canvas_cel(target,target_layer,${targetFrame})
|
|
127
|
+
local target_image=target_cel.image
|
|
128
|
+
local function transformed_source(dx,dy)
|
|
129
|
+
local rx=dx local ry=dy
|
|
130
|
+
if rotation==90 then rx=dy ry=scaled_height-1-dx
|
|
131
|
+
elseif rotation==180 then rx=scaled_width-1-dx ry=scaled_height-1-dy
|
|
132
|
+
elseif rotation==270 then rx=scaled_width-1-dy ry=dx end
|
|
133
|
+
if ${input.flipX === true ? "true" : "false"} then rx=scaled_width-1-rx end
|
|
134
|
+
if ${input.flipY === true ? "true" : "false"} then ry=scaled_height-1-ry end
|
|
135
|
+
local sx=${region.x}+math.floor(rx/${scale})
|
|
136
|
+
local sy=${region.y}+math.floor(ry/${scale})
|
|
137
|
+
return pixel_rgba(source,source_image:getPixel(sx,sy))
|
|
138
|
+
end
|
|
139
|
+
local blend=${luaString(input.blend ?? "replace")}
|
|
140
|
+
local changed=0
|
|
141
|
+
for dy=0,output_height-1 do for dx=0,output_width-1 do
|
|
142
|
+
local tx=${targetX}+dx local ty=${targetY}+dy
|
|
143
|
+
if tx>=0 and ty>=0 and tx<target.width and ty<target.height then
|
|
144
|
+
local src=transformed_source(dx,dy)
|
|
145
|
+
local dst=pixel_rgba(target,target_image:getPixel(tx,ty))
|
|
146
|
+
local write=nil
|
|
147
|
+
if blend=="replace" then write=src
|
|
148
|
+
elseif blend=="behind" then if dst.a==0 then write=src end
|
|
149
|
+
elseif src.a>0 then
|
|
150
|
+
if src.a==255 then write=src
|
|
151
|
+
else
|
|
152
|
+
local sa=src.a/255 local da=dst.a/255 local oa=sa+da*(1-sa)
|
|
153
|
+
if oa>0 then write={r=math.floor((src.r*sa+dst.r*da*(1-sa))/oa+0.5),g=math.floor((src.g*sa+dst.g*da*(1-sa))/oa+0.5),b=math.floor((src.b*sa+dst.b*da*(1-sa))/oa+0.5),a=math.floor(oa*255+0.5)} end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
if write~=nil then target_image:drawPixel(tx,ty,color_pixel(target,write)) changed=changed+1 end
|
|
157
|
+
end
|
|
158
|
+
end end
|
|
159
|
+
if not target:saveAs(${luaString(target.absolute)}) then fail("Unable to save target sprite") end
|
|
160
|
+
emit_result({target=${luaString(target.relative)},source=${luaString(source.relative)},changed_pixels=changed,output_bounds={x=${targetX},y=${targetY},width=output_width,height=output_height},layer=target_layer.name,frame=${targetFrame}})
|
|
161
|
+
if source~=target then source:close() end target:close()
|
|
162
|
+
`);
|
|
163
|
+
return textResponse(result);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export async function asepriteDrawStroke(config, registry, input) {
|
|
170
|
+
try {
|
|
171
|
+
if (!Array.isArray(input.points) || input.points.length < 1 || input.points.length > MAX_STROKE_POINTS) {
|
|
172
|
+
throw new Error(`points must contain 1-${MAX_STROKE_POINTS} entries.`);
|
|
173
|
+
}
|
|
174
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, "draw-stroke");
|
|
175
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
176
|
+
const frame = assertPositiveInteger(input.frame ?? 1, "frame");
|
|
177
|
+
const points = input.points.map((point) => ({
|
|
178
|
+
x: assertInteger(point.x, "point.x"),
|
|
179
|
+
y: assertInteger(point.y, "point.y"),
|
|
180
|
+
pressure: point.pressure === undefined ? undefined : Math.max(0, Math.min(1, point.pressure)),
|
|
181
|
+
}));
|
|
182
|
+
const size = Math.min(256, assertPositiveInteger(input.brush?.size ?? 1, "brush.size"));
|
|
183
|
+
const angle = assertInteger(input.brush?.angle ?? 0, "brush.angle");
|
|
184
|
+
const opacity = Math.max(0, Math.min(255, assertInteger(input.opacity ?? 255, "opacity")));
|
|
185
|
+
const pointLua = `{${points.map((point) => `Point(${point.x},${point.y})`).join(",")}}`;
|
|
186
|
+
const color = input.color ? luaColor(input.color) : "{r=0,g=0,b=0,a=255}";
|
|
187
|
+
const brushType = input.brush?.type ?? "circle";
|
|
188
|
+
const brushTypeLua = brushType === "square" ? "BrushType.SQUARE" : brushType === "line" ? "BrushType.LINE" : "BrushType.CIRCLE";
|
|
189
|
+
const customBrush = input.brush?.imagePath ? workspacePath(registry, input.workspaceId, input.brush.imagePath) : undefined;
|
|
190
|
+
const inkLua = input.ink === "alpha" ? "Ink.ALPHA_COMPOSITING"
|
|
191
|
+
: input.ink === "copy" ? "Ink.COPY_COLOR"
|
|
192
|
+
: input.ink === "lock_alpha" ? "Ink.LOCK_ALPHA"
|
|
193
|
+
: input.ink === "shading" ? "Ink.SHADING"
|
|
194
|
+
: "Ink.SIMPLE";
|
|
195
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
196
|
+
${openSpriteScript(file.absolute)}
|
|
197
|
+
if ${frame}>#sprite.frames then fail("Frame is outside the sprite") end
|
|
198
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "sprite.layers[1]"}
|
|
199
|
+
if layer==nil or layer.isGroup then fail("Drawable layer was not found") end
|
|
200
|
+
app.activeLayer=layer app.activeFrame=sprite.frames[${frame}]
|
|
201
|
+
ensure_canvas_cel(sprite,layer,${frame})
|
|
202
|
+
local brush=nil
|
|
203
|
+
${customBrush ? `
|
|
204
|
+
local brush_sprite=app.open(${luaString(customBrush.absolute)})
|
|
205
|
+
if brush_sprite==nil then fail("Unable to open custom brush image") end
|
|
206
|
+
local brush_image=Image(brush_sprite.spec) brush_image:clear() brush_image:drawSprite(brush_sprite,1,Point(0,0))
|
|
207
|
+
brush=Brush{type=BrushType.IMAGE,image=brush_image}
|
|
208
|
+
app.activeSprite=sprite app.activeLayer=layer app.activeFrame=sprite.frames[${frame}]
|
|
209
|
+
` : `brush=Brush{type=${brushTypeLua},size=${size},angle=${angle}}`}
|
|
210
|
+
local prefs=app.preferences
|
|
211
|
+
local doc_prefs=prefs.document(sprite)
|
|
212
|
+
prefs.symmetry_mode.enabled=${input.symmetry ? "true" : "false"}
|
|
213
|
+
doc_prefs.symmetry.mode=${input.symmetry ? ((input.symmetry.horizontalX !== undefined ? 1 : 0) + (input.symmetry.verticalY !== undefined ? 2 : 0)) : 0}
|
|
214
|
+
doc_prefs.symmetry.x_axis=${input.symmetry?.horizontalX ?? "math.floor(sprite.width/2)"}
|
|
215
|
+
doc_prefs.symmetry.y_axis=${input.symmetry?.verticalY ?? "math.floor(sprite.height/2)"}
|
|
216
|
+
doc_prefs.tiled.mode=${(input.tiled?.horizontal ? 1 : 0) + (input.tiled?.vertical ? 2 : 0)}
|
|
217
|
+
local color=Color(${color})
|
|
218
|
+
app.useTool{
|
|
219
|
+
tool=${luaString(input.tool ?? "pencil")},
|
|
220
|
+
freehandAlgorithm=${input.pixelPerfect === true ? 1 : 0},
|
|
221
|
+
brush=brush,
|
|
222
|
+
color=color,
|
|
223
|
+
points=${pointLua},
|
|
224
|
+
ink=${inkLua},
|
|
225
|
+
opacity=${opacity},
|
|
226
|
+
}
|
|
227
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end
|
|
228
|
+
emit_result({file=${luaString(file.relative)},layer=layer.name,frame=${frame},points=${points.length},tool=${luaString(input.tool ?? "pencil")},brush={type=${luaString(brushType)},size=${size},angle=${angle}},pixel_perfect=${input.pixelPerfect === true ? "true" : "false"}})
|
|
229
|
+
${customBrush ? "brush_sprite:close()" : ""} sprite:close()
|
|
230
|
+
`);
|
|
231
|
+
return textResponse(result);
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export async function asepriteComposeLayers(config, registry, input) {
|
|
238
|
+
try {
|
|
239
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `layers-${input.action}`);
|
|
240
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
241
|
+
const blendMap = {
|
|
242
|
+
normal: "BlendMode.NORMAL", multiply: "BlendMode.MULTIPLY", screen: "BlendMode.SCREEN",
|
|
243
|
+
overlay: "BlendMode.OVERLAY", darken: "BlendMode.DARKEN", lighten: "BlendMode.LIGHTEN",
|
|
244
|
+
addition: "BlendMode.ADDITION", subtract: "BlendMode.SUBTRACT", divide: "BlendMode.DIVIDE",
|
|
245
|
+
};
|
|
246
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
247
|
+
${openSpriteScript(file.absolute)}
|
|
248
|
+
local action=${luaString(input.action)}
|
|
249
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "nil"}
|
|
250
|
+
if action=="create_group" then
|
|
251
|
+
local group=sprite:newGroup() group.name=${luaString(input.name?.trim() || "Group")}
|
|
252
|
+
elseif layer==nil then fail("Layer was not found")
|
|
253
|
+
elseif action=="duplicate" then
|
|
254
|
+
app.activeLayer=layer app.command.DuplicateLayer()
|
|
255
|
+
if ${input.name ? "true" : "false"} then app.activeLayer.name=${luaString(input.name ?? "Layer Copy")} end
|
|
256
|
+
elseif action=="merge_down" then app.activeLayer=layer app.command.MergeDownLayer()
|
|
257
|
+
elseif action=="flatten_all" then sprite:flatten()
|
|
258
|
+
elseif action=="flatten_visible" then
|
|
259
|
+
local hidden={}
|
|
260
|
+
local function visit(items) for _,candidate in ipairs(items) do if not candidate.isVisible then table.insert(hidden,candidate) end if candidate.isGroup then visit(candidate.layers) end end end
|
|
261
|
+
visit(sprite.layers)
|
|
262
|
+
sprite:flatten()
|
|
263
|
+
elseif action=="to_background" then app.activeLayer=layer app.command.BackgroundFromLayer()
|
|
264
|
+
elseif action=="from_background" then app.activeLayer=layer app.command.LayerFromBackground()
|
|
265
|
+
elseif action=="reorder" then layer.stackIndex=${input.stackIndex ?? 1}
|
|
266
|
+
elseif action=="move_to_group" then
|
|
267
|
+
local group=find_layer(sprite.layers,${luaString(input.group ?? "")})
|
|
268
|
+
if group==nil or not group.isGroup then fail("Target group was not found") end
|
|
269
|
+
layer.parent=group
|
|
270
|
+
elseif action=="set_locked" then layer.isEditable=${input.locked === false ? "true" : "false"}
|
|
271
|
+
elseif action=="set_blend_mode" then layer.blendMode=${blendMap[input.blendMode ?? "normal"]}
|
|
272
|
+
elseif action=="solo" then
|
|
273
|
+
local function visit(items) for _,candidate in ipairs(items) do candidate.isVisible=(candidate==layer or candidate.isGroup) if candidate.isGroup then visit(candidate.layers) end end end
|
|
274
|
+
visit(sprite.layers) layer.isVisible=true
|
|
275
|
+
else fail("Unsupported layer composition action") end
|
|
276
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end
|
|
277
|
+
emit_result(sprite_summary(sprite)) sprite:close()
|
|
278
|
+
`);
|
|
279
|
+
return textResponse(result);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function readMask(registry, workspaceId, path) {
|
|
286
|
+
const file = workspacePath(registry, workspaceId, path);
|
|
287
|
+
const parsed = JSON.parse(await readFile(file.absolute, "utf8"));
|
|
288
|
+
if (parsed.format !== "auvrynt-aseprite-mask-v1" || !Array.isArray(parsed.points))
|
|
289
|
+
throw new Error("Invalid Auvrynt Aseprite mask file.");
|
|
290
|
+
if (parsed.points.length > MAX_MASK_POINTS)
|
|
291
|
+
throw new Error("Mask contains too many points.");
|
|
292
|
+
return parsed;
|
|
293
|
+
}
|
|
294
|
+
export async function asepriteManageMask(config, registry, input) {
|
|
295
|
+
try {
|
|
296
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
297
|
+
const maskFile = workspacePath(registry, input.workspaceId, input.maskPath);
|
|
298
|
+
const frame = assertPositiveInteger(input.frame ?? 1, "frame");
|
|
299
|
+
if (input.action === "inspect")
|
|
300
|
+
return textResponse(await readMask(registry, input.workspaceId, input.maskPath));
|
|
301
|
+
let existing;
|
|
302
|
+
if (["invert", "move", "apply_clear", "apply_fill"].includes(input.action))
|
|
303
|
+
existing = await readMask(registry, input.workspaceId, input.maskPath);
|
|
304
|
+
if (input.action === "move") {
|
|
305
|
+
const dx = assertInteger(input.dx ?? 0, "dx");
|
|
306
|
+
const dy = assertInteger(input.dy ?? 0, "dy");
|
|
307
|
+
if (input.movePixels) {
|
|
308
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, "move-mask-pixels");
|
|
309
|
+
const pointsLua = `{${existing.points.map((point) => `{x=${point.x},y=${point.y}}`).join(",")}}`;
|
|
310
|
+
await runLua(config, registry, input.workspaceId, `
|
|
311
|
+
${openSpriteScript(file.absolute)}
|
|
312
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "sprite.layers[1]"}
|
|
313
|
+
if layer==nil or layer.isGroup then fail("Drawable layer was not found") end
|
|
314
|
+
local cel=ensure_canvas_cel(sprite,layer,${frame}) local image=cel.image
|
|
315
|
+
local points=${pointsLua} local captured={}
|
|
316
|
+
for _,point in ipairs(points) do if point.x>=0 and point.y>=0 and point.x<sprite.width and point.y<sprite.height then table.insert(captured,{x=point.x,y=point.y,p=image:getPixel(point.x,point.y)}) image:drawPixel(point.x,point.y,sprite.colorMode==ColorMode.INDEXED and sprite.transparentColor or 0) end end
|
|
317
|
+
for _,point in ipairs(captured) do local x=point.x+${dx} local y=point.y+${dy} if x>=0 and y>=0 and x<sprite.width and y<sprite.height then image:drawPixel(x,y,point.p) end end
|
|
318
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result({moved=#captured}) sprite:close()
|
|
319
|
+
`);
|
|
320
|
+
}
|
|
321
|
+
const moved = { ...existing, points: existing.points.map((point) => ({ x: point.x + dx, y: point.y + dy })) };
|
|
322
|
+
await mkdir(dirname(maskFile.absolute), { recursive: true });
|
|
323
|
+
await writeFile(maskFile.absolute, JSON.stringify(moved, null, 2), "utf8");
|
|
324
|
+
return textResponse({ mask: maskFile.relative, points: moved.points.length, dx, dy, movedPixels: input.movePixels === true });
|
|
325
|
+
}
|
|
326
|
+
if (input.action === "apply_clear" || input.action === "apply_fill") {
|
|
327
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `mask-${input.action}`);
|
|
328
|
+
const pointsLua = `{${existing.points.map((point) => `{x=${point.x},y=${point.y}}`).join(",")}}`;
|
|
329
|
+
const fill = input.action === "apply_fill" ? luaColor(input.fillColor ?? "#000000FF") : undefined;
|
|
330
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
331
|
+
${openSpriteScript(file.absolute)}
|
|
332
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "sprite.layers[1]"}
|
|
333
|
+
if layer==nil or layer.isGroup then fail("Drawable layer was not found") end
|
|
334
|
+
local image=ensure_canvas_cel(sprite,layer,${frame}).image local points=${pointsLua}
|
|
335
|
+
local pixel=${fill ? `color_pixel(sprite,${fill})` : "sprite.colorMode==ColorMode.INDEXED and sprite.transparentColor or 0"}
|
|
336
|
+
local changed=0
|
|
337
|
+
for _,point in ipairs(points) do if point.x>=0 and point.y>=0 and point.x<sprite.width and point.y<sprite.height then image:drawPixel(point.x,point.y,pixel) changed=changed+1 end end
|
|
338
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result({changed_pixels=changed}) sprite:close()
|
|
339
|
+
`);
|
|
340
|
+
return textResponse(result);
|
|
341
|
+
}
|
|
342
|
+
const rect = input.rect ? normalizeRegion(input.rect) : undefined;
|
|
343
|
+
const targetColor = input.color ? parseColor(input.color) : undefined;
|
|
344
|
+
const tolerance = Math.max(0, Math.min(255, assertInteger(input.tolerance ?? 0, "tolerance")));
|
|
345
|
+
const currentPoints = existing?.points ?? [];
|
|
346
|
+
const pointsLua = `{${currentPoints.map((point) => `{x=${point.x},y=${point.y}}`).join(",")}}`;
|
|
347
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
348
|
+
${openSpriteScript(file.absolute)}
|
|
349
|
+
local points={}
|
|
350
|
+
local selected={}
|
|
351
|
+
local function add(x,y) local key=x..","..y if not selected[key] then selected[key]=true table.insert(points,{x=x,y=y}) end end
|
|
352
|
+
if ${luaString(input.action)}=="create_rect" then
|
|
353
|
+
local x=${rect?.x ?? 0} local y=${rect?.y ?? 0} local width=${rect?.width ?? 0} local height=${rect?.height ?? 0}
|
|
354
|
+
if x<0 or y<0 or x+width>sprite.width or y+height>sprite.height then fail("Mask rectangle is outside the sprite") end
|
|
355
|
+
for py=y,y+height-1 do for px=x,x+width-1 do add(px,py) end end
|
|
356
|
+
elseif ${luaString(input.action)}=="invert" then
|
|
357
|
+
local old=${pointsLua} for _,point in ipairs(old) do selected[point.x..","..point.y]=true end
|
|
358
|
+
local inverted={} for y=0,sprite.height-1 do for x=0,sprite.width-1 do if not selected[x..","..y] then table.insert(inverted,{x=x,y=y}) end end end points=inverted
|
|
359
|
+
else
|
|
360
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "sprite.layers[1]"}
|
|
361
|
+
if layer==nil or layer.isGroup then fail("Drawable layer was not found") end
|
|
362
|
+
for y=0,sprite.height-1 do for x=0,sprite.width-1 do
|
|
363
|
+
local c=canvas_pixel(sprite,layer,${frame},x,y)
|
|
364
|
+
if ${luaString(input.action)}=="create_opaque" then if c.a>0 then add(x,y) end
|
|
365
|
+
else
|
|
366
|
+
local target=${targetColor ? `{r=${targetColor.r},g=${targetColor.g},b=${targetColor.b},a=${targetColor.a}}` : "{r=0,g=0,b=0,a=0}"}
|
|
367
|
+
if math.abs(c.r-target.r)<=${tolerance} and math.abs(c.g-target.g)<=${tolerance} and math.abs(c.b-target.b)<=${tolerance} and math.abs(c.a-target.a)<=${tolerance} then add(x,y) end
|
|
368
|
+
end
|
|
369
|
+
end end
|
|
370
|
+
end
|
|
371
|
+
if #points>${MAX_MASK_POINTS} then fail("Generated mask exceeds ${MAX_MASK_POINTS} points") end
|
|
372
|
+
emit_result({spriteWidth=sprite.width,spriteHeight=sprite.height,points=points}) sprite:close()
|
|
373
|
+
`);
|
|
374
|
+
const stored = { format: "auvrynt-aseprite-mask-v1", ...result };
|
|
375
|
+
await mkdir(dirname(maskFile.absolute), { recursive: true });
|
|
376
|
+
await writeFile(maskFile.absolute, JSON.stringify(stored, null, 2), "utf8");
|
|
377
|
+
return textResponse({ mask: maskFile.relative, points: stored.points.length, spriteWidth: stored.spriteWidth, spriteHeight: stored.spriteHeight });
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
export async function asepriteManageColor(config, registry, input) {
|
|
384
|
+
try {
|
|
385
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
386
|
+
if (input.action === "inspect") {
|
|
387
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
388
|
+
${openSpriteScript(file.absolute)}
|
|
389
|
+
local colors={}
|
|
390
|
+
if #sprite.palettes>0 then local palette=sprite.palettes[1] for index=0,#palette-1 do local c=palette:getColor(index) table.insert(colors,{index=index,color=rgba_hex({r=c.red,g=c.green,b=c.blue,a=(index==sprite.transparentColor and 0 or c.alpha)})}) end end
|
|
391
|
+
emit_result({file=${luaString(file.relative)},color_mode=color_mode_name(sprite.colorMode),color_profile=sprite.colorSpace and sprite.colorSpace.name or nil,transparent_index=sprite.transparentColor,palette=colors}) sprite:close()
|
|
392
|
+
`);
|
|
393
|
+
return textResponse(result);
|
|
394
|
+
}
|
|
395
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `color-${input.action}`);
|
|
396
|
+
if (input.action === "quantize") {
|
|
397
|
+
const executable = await resolveAsepriteExecutable(config);
|
|
398
|
+
const temporary = `${file.absolute}.auvrynt-quantized.aseprite`;
|
|
399
|
+
const args = ["-b", file.absolute];
|
|
400
|
+
if (input.palettePath)
|
|
401
|
+
args.push("--palette", workspacePath(registry, input.workspaceId, input.palettePath).absolute);
|
|
402
|
+
args.push("--color-mode", "indexed", "--dithering-algorithm", input.dithering ?? "none");
|
|
403
|
+
if (input.ditheringMatrix)
|
|
404
|
+
args.push("--dithering-matrix", input.ditheringMatrix);
|
|
405
|
+
args.push("--save-as", temporary);
|
|
406
|
+
await execFileAsync(executable, args, { timeout: 120_000, windowsHide: true });
|
|
407
|
+
if (input.maxColors && !input.palettePath) {
|
|
408
|
+
await runLua(config, registry, input.workspaceId, `
|
|
409
|
+
${openSpriteScript(temporary)}
|
|
410
|
+
app.command.ColorQuantization{ui=false,withAlpha=true,maxColors=${Math.max(2, Math.min(256, assertInteger(input.maxColors, "maxColors")))}}
|
|
411
|
+
if not sprite:saveAs(${luaString(temporary)}) then fail("Unable to save quantized sprite") end emit_result({ok=true}) sprite:close()
|
|
412
|
+
`);
|
|
413
|
+
}
|
|
414
|
+
await rename(temporary, file.absolute);
|
|
415
|
+
return textResponse({ file: file.relative, quantized: true, version: await assertAsepriteExpectedVersion(registry, input.workspaceId, input.filePath) });
|
|
416
|
+
}
|
|
417
|
+
const palette = input.palettePath ? workspacePath(registry, input.workspaceId, input.palettePath) : undefined;
|
|
418
|
+
const profile = input.profilePath ? workspacePath(registry, input.workspaceId, input.profilePath) : undefined;
|
|
419
|
+
const from = input.fromColor ? parseColor(input.fromColor) : undefined;
|
|
420
|
+
const to = input.toColor ? parseColor(input.toColor) : undefined;
|
|
421
|
+
const tolerance = Math.max(0, Math.min(255, assertInteger(input.tolerance ?? 0, "tolerance")));
|
|
422
|
+
const presetColors = input.preset ? getAsepritePalettePreset(input.preset) : undefined;
|
|
423
|
+
const presetLua = presetColors ? `{${presetColors.map((color) => {
|
|
424
|
+
const parsed = parseColor(color);
|
|
425
|
+
return `{r=${parsed.r},g=${parsed.g},b=${parsed.b},a=${parsed.a}}`;
|
|
426
|
+
}).join(",")}}` : "nil";
|
|
427
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
428
|
+
${openSpriteScript(file.absolute)}
|
|
429
|
+
local action=${luaString(input.action)}
|
|
430
|
+
if action=="apply_palette_preset" then
|
|
431
|
+
if ${presetLua}==nil then fail("preset is required") end
|
|
432
|
+
local colors=${presetLua} local new_palette=Palette(#colors)
|
|
433
|
+
for index,color in ipairs(colors) do new_palette:setColor(index-1,Color(color)) end
|
|
434
|
+
sprite:setPalette(new_palette)
|
|
435
|
+
elseif action=="set_palette_entry" then
|
|
436
|
+
local index=${input.index ?? -1} if index<0 or #sprite.palettes==0 or index>=#sprite.palettes[1] then fail("Palette index is outside the palette") end
|
|
437
|
+
sprite.palettes[1]:setColor(index,Color(${input.color ? luaColor(input.color) : "{r=0,g=0,b=0,a=255}"}))
|
|
438
|
+
elseif action=="set_transparent_index" then
|
|
439
|
+
if sprite.colorMode~=ColorMode.INDEXED then fail("Transparent index is only valid for indexed sprites") end
|
|
440
|
+
local index=${input.index ?? -1} if index<0 or index>=#sprite.palettes[1] then fail("Transparent index is outside the palette") end sprite.transparentColor=index
|
|
441
|
+
elseif action=="remap_color" then
|
|
442
|
+
local from=${from ? `{r=${from.r},g=${from.g},b=${from.b},a=${from.a}}` : "nil"} local replacement=${to ? `{r=${to.r},g=${to.g},b=${to.b},a=${to.a}}` : "nil"}
|
|
443
|
+
if from==nil or replacement==nil then fail("fromColor and toColor are required") end
|
|
444
|
+
local changed=0
|
|
445
|
+
for _,cel in ipairs(sprite.cels) do for pixel in cel.image:pixels() do local c=pixel_rgba(sprite,pixel()) if math.abs(c.r-from.r)<=${tolerance} and math.abs(c.g-from.g)<=${tolerance} and math.abs(c.b-from.b)<=${tolerance} and math.abs(c.a-from.a)<=${tolerance} then pixel(color_pixel(sprite,replacement)) changed=changed+1 end end end
|
|
446
|
+
elseif action=="assign_profile" or action=="convert_profile" then
|
|
447
|
+
local cs=${profile ? `ColorSpace{fromFile=${luaString(profile.absolute)}}` : "ColorSpace{sRGB=true}"}
|
|
448
|
+
if action=="assign_profile" then sprite:assignColorSpace(cs) else sprite:convertColorSpace(cs) end
|
|
449
|
+
elseif action=="remove_profile" then sprite:assignColorSpace(ColorSpace())
|
|
450
|
+
elseif action=="load_palette" then sprite:setPalette(Palette{fromFile=${luaString(palette?.absolute ?? "")}})
|
|
451
|
+
elseif action=="save_palette" then app.command.SavePalette{ui=false,filename=${luaString(palette?.absolute ?? "")},columns=16}
|
|
452
|
+
else fail("Unsupported color action") end
|
|
453
|
+
if action~="save_palette" and not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end
|
|
454
|
+
emit_result({file=${luaString(file.relative)},action=action,color_profile=sprite.colorSpace and sprite.colorSpace.name or nil,transparent_index=sprite.transparentColor,palette_size=#sprite.palettes>0 and #sprite.palettes[1] or 0}) sprite:close()
|
|
455
|
+
`);
|
|
456
|
+
return textResponse(result);
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
export async function asepriteManageDocument(config, registry, input) {
|
|
463
|
+
try {
|
|
464
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `document-${input.action}`);
|
|
465
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
466
|
+
const properties = input.properties ?? {};
|
|
467
|
+
const propertiesLua = `{${Object.entries(properties).map(([key, value]) => {
|
|
468
|
+
const encoded = value === null ? "nil" : typeof value === "string" ? luaString(value) : String(value);
|
|
469
|
+
return `[${luaString(key)}]=${encoded}`;
|
|
470
|
+
}).join(",")}}`;
|
|
471
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
472
|
+
${openSpriteScript(file.absolute)}
|
|
473
|
+
local action=${luaString(input.action)}
|
|
474
|
+
if action=="resize_sprite" then sprite:resize(${input.width ?? 0},${input.height ?? 0})
|
|
475
|
+
elseif action=="resize_canvas" then
|
|
476
|
+
local old_width=sprite.width local old_height=sprite.height sprite.width=${input.width ?? 0} sprite.height=${input.height ?? 0}
|
|
477
|
+
for _,cel in ipairs(sprite.cels) do cel.position=Point(cel.position.x+${input.offsetX ?? 0},cel.position.y+${input.offsetY ?? 0}) end
|
|
478
|
+
elseif action=="crop" then sprite:crop{x=${input.region?.x ?? 0},y=${input.region?.y ?? 0},width=${input.region?.width ?? 0},height=${input.region?.height ?? 0}}
|
|
479
|
+
elseif action=="trim" then
|
|
480
|
+
local bounds=nil
|
|
481
|
+
for frame=1,#sprite.frames do local render=Image(sprite.spec) render:clear() render:drawSprite(sprite,frame,Point(0,0)) for y=0,sprite.height-1 do for x=0,sprite.width-1 do if pixel_rgba(sprite,render:getPixel(x,y)).a>0 then if bounds==nil then bounds={x=x,y=y,right=x,bottom=y} else if x<bounds.x then bounds.x=x end if y<bounds.y then bounds.y=y end if x>bounds.right then bounds.right=x end if y>bounds.bottom then bounds.bottom=y end end end end end end
|
|
482
|
+
if bounds~=nil then sprite:crop{x=bounds.x,y=bounds.y,width=bounds.right-bounds.x+1,height=bounds.bottom-bounds.y+1} end
|
|
483
|
+
elseif action=="set_grid" then sprite.gridBounds=Rectangle(${input.grid?.x ?? 0},${input.grid?.y ?? 0},${input.grid?.width ?? 16},${input.grid?.height ?? 16})
|
|
484
|
+
elseif action=="set_pixel_ratio" then sprite.pixelRatio=Size(${input.ratioWidth ?? 1},${input.ratioHeight ?? 1})
|
|
485
|
+
elseif action=="set_userdata" then
|
|
486
|
+
local target=sprite local target_type=${luaString(input.targetType ?? "sprite")}
|
|
487
|
+
if target_type=="layer" then target=find_layer(sprite.layers,${luaString(input.targetName ?? "")})
|
|
488
|
+
elseif target_type=="cel" then local layer=find_layer(sprite.layers,${luaString(input.targetName ?? "")}) target=layer and layer:cel(${input.frame ?? 1}) or nil
|
|
489
|
+
elseif target_type=="tag" then for _,item in ipairs(sprite.tags) do if item.name==${luaString(input.targetName ?? "")} then target=item break end end
|
|
490
|
+
elseif target_type=="slice" then for _,item in ipairs(sprite.slices) do if item.name==${luaString(input.targetName ?? "")} then target=item break end end end
|
|
491
|
+
if target==nil then fail("User-data target was not found") end
|
|
492
|
+
target.data=${luaString(input.data ?? "")} target.properties=${propertiesLua}
|
|
493
|
+
elseif action=="create_slice" then
|
|
494
|
+
local region=Rectangle(${input.region?.x ?? 0},${input.region?.y ?? 0},${input.region?.width ?? 1},${input.region?.height ?? 1})
|
|
495
|
+
local slice=sprite:newSlice(region) slice.name=${luaString(input.sliceName ?? "Slice")}
|
|
496
|
+
${input.center ? `slice.center=Rectangle(${input.center.x},${input.center.y},${input.center.width},${input.center.height})` : ""}
|
|
497
|
+
${input.pivot ? `slice.pivot=Point(${input.pivot.x},${input.pivot.y})` : ""}
|
|
498
|
+
elseif action=="update_slice" then
|
|
499
|
+
local slice=nil for _,item in ipairs(sprite.slices) do if item.name==${luaString(input.sliceName ?? "")} then slice=item break end end if slice==nil then fail("Slice was not found") end
|
|
500
|
+
${input.region ? `slice.bounds=Rectangle(${input.region.x},${input.region.y},${input.region.width},${input.region.height})` : ""}
|
|
501
|
+
${input.center ? `slice.center=Rectangle(${input.center.x},${input.center.y},${input.center.width},${input.center.height})` : ""}
|
|
502
|
+
${input.pivot ? `slice.pivot=Point(${input.pivot.x},${input.pivot.y})` : ""}
|
|
503
|
+
elseif action=="delete_slice" then
|
|
504
|
+
local slice=nil for _,item in ipairs(sprite.slices) do if item.name==${luaString(input.sliceName ?? "")} then slice=item break end end if slice==nil then fail("Slice was not found") end sprite:deleteSlice(slice)
|
|
505
|
+
else fail("Unsupported document action") end
|
|
506
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result(sprite_summary(sprite)) sprite:close()
|
|
507
|
+
`);
|
|
508
|
+
return textResponse(result);
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
export async function asepriteManageCels(config, registry, input) {
|
|
515
|
+
try {
|
|
516
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
517
|
+
const frame = assertPositiveInteger(input.frame, "frame");
|
|
518
|
+
if (input.action !== "inspect")
|
|
519
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `cel-${input.action}`);
|
|
520
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
521
|
+
${openSpriteScript(file.absolute)}
|
|
522
|
+
local layer=find_layer(sprite.layers,${luaString(input.layer)}) if layer==nil or layer.isGroup then fail("Layer was not found") end
|
|
523
|
+
if ${frame}>#sprite.frames then fail("Frame is outside the sprite") end
|
|
524
|
+
local cel=layer:cel(${frame}) local action=${luaString(input.action)}
|
|
525
|
+
if action=="inspect" then
|
|
526
|
+
emit_result({exists=cel~=nil,cel=cel and {layer=layer.name,frame=${frame},x=cel.position.x,y=cel.position.y,width=cel.image.width,height=cel.image.height,opacity=cel.opacity,z_index=cel.zIndex,image_id=tostring(cel.image.id or cel.image),data=cel.data} or nil}) sprite:close() return
|
|
527
|
+
elseif action=="create" then if cel==nil then cel=sprite:newCel(layer,${frame},Image(sprite.spec),Point(${input.x ?? 0},${input.y ?? 0})) end
|
|
528
|
+
elseif cel==nil then fail("Cel was not found")
|
|
529
|
+
elseif action=="delete" then sprite:deleteCel(cel)
|
|
530
|
+
elseif action=="move" then cel.position=Point(${input.x ?? 0},${input.y ?? 0})
|
|
531
|
+
elseif action=="set_opacity" then cel.opacity=${input.opacity ?? 255}
|
|
532
|
+
elseif action=="set_z_index" then cel.zIndex=${input.zIndex ?? 0}
|
|
533
|
+
elseif action=="duplicate" or action=="link" then
|
|
534
|
+
local target_layer=find_layer(sprite.layers,${luaString(input.targetLayer ?? input.layer)}) if target_layer==nil or target_layer.isGroup then fail("Target layer was not found") end
|
|
535
|
+
local target_frame=${input.targetFrame ?? frame} if target_frame>#sprite.frames then fail("Target frame is outside the sprite") end
|
|
536
|
+
local existing=target_layer:cel(target_frame) if existing~=nil then sprite:deleteCel(existing) end
|
|
537
|
+
local image=action=="link" and cel.image or Image(cel.image)
|
|
538
|
+
local target=sprite:newCel(target_layer,target_frame,image,Point(cel.position.x,cel.position.y)) target.opacity=cel.opacity target.zIndex=cel.zIndex
|
|
539
|
+
elseif action=="unlink" then cel.image=Image(cel.image)
|
|
540
|
+
else fail("Unsupported cel action") end
|
|
541
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result(sprite_summary(sprite)) sprite:close()
|
|
542
|
+
`);
|
|
543
|
+
return textResponse(result);
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
export async function asepriteManageAnimation(config, registry, input) {
|
|
550
|
+
try {
|
|
551
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `animation-${input.action}`);
|
|
552
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
553
|
+
const durationLua = `{${(input.durations ?? []).map((item) => `{frame=${assertPositiveInteger(item.frame, "duration.frame")},duration=${Math.max(1, Math.min(60000, assertInteger(item.durationMs, "duration.durationMs"))) / 1000}}`).join(",")}}`;
|
|
554
|
+
const directionLua = input.direction === "reverse" ? "AniDir.REVERSE" : input.direction === "ping_pong" ? "AniDir.PING_PONG" : "AniDir.FORWARD";
|
|
555
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
556
|
+
${openSpriteScript(file.absolute)}
|
|
557
|
+
local action=${luaString(input.action)}
|
|
558
|
+
if action=="set_durations" then for _,item in ipairs(${durationLua}) do if item.frame>#sprite.frames then fail("Duration frame is outside the sprite") end sprite.frames[item.frame].duration=item.duration end
|
|
559
|
+
elseif action=="update_tag" then
|
|
560
|
+
local tag=nil for _,item in ipairs(sprite.tags) do if item.name==${luaString(input.tagName ?? "")} then tag=item break end end if tag==nil then fail("Tag was not found") end
|
|
561
|
+
${input.newName ? `tag.name=${luaString(input.newName)}` : ""} tag.aniDir=${directionLua} ${input.repeats !== undefined ? `tag.repeats=${Math.max(0, assertInteger(input.repeats, "repeats"))}` : ""}
|
|
562
|
+
${input.from !== undefined && input.to !== undefined ? `tag.fromFrame=sprite.frames[${input.from}] tag.toFrame=sprite.frames[${input.to}]` : ""}
|
|
563
|
+
elseif action=="tween_cel_position" then
|
|
564
|
+
local layer=find_layer(sprite.layers,${luaString(input.layer ?? "")})
|
|
565
|
+
if layer==nil or layer.isGroup then fail("A drawable layer is required") end
|
|
566
|
+
local first=${input.from ?? 1} local last=${input.to ?? 1}
|
|
567
|
+
if first<1 or last>#sprite.frames or first>=last then fail("A valid tween frame range is required") end
|
|
568
|
+
local first_cel=layer:cel(first)
|
|
569
|
+
if first_cel==nil then fail("The first tween frame has no cel on the selected layer") end
|
|
570
|
+
local start_x=first_cel.position.x local start_y=first_cel.position.y
|
|
571
|
+
local end_x=${input.targetX ?? 0} local end_y=${input.targetY ?? 0}
|
|
572
|
+
local easing=${luaString(input.easing ?? "smoothstep")}
|
|
573
|
+
local function ease(t)
|
|
574
|
+
if easing=="ease_in" then return t*t end
|
|
575
|
+
if easing=="ease_out" then return 1-(1-t)*(1-t) end
|
|
576
|
+
if easing=="smoothstep" then return t*t*(3-2*t) end
|
|
577
|
+
return t
|
|
578
|
+
end
|
|
579
|
+
for frame_number=first,last do
|
|
580
|
+
local cel=layer:cel(frame_number)
|
|
581
|
+
if cel~=nil then local t=ease((frame_number-first)/(last-first)) cel.position=Point(math.floor(start_x+(end_x-start_x)*t+0.5),math.floor(start_y+(end_y-start_y)*t+0.5)) end
|
|
582
|
+
end
|
|
583
|
+
else
|
|
584
|
+
local frame=${input.frame ?? input.from ?? 1} local target=${input.targetFrame ?? input.to ?? 1}
|
|
585
|
+
if frame<1 or frame>#sprite.frames or target<1 or target>#sprite.frames then fail("Frame is outside the sprite") end
|
|
586
|
+
if action=="copy_frame" or action=="move_frame" then
|
|
587
|
+
local source_frame=sprite.frames[frame]
|
|
588
|
+
local duration=source_frame.duration
|
|
589
|
+
local stored={}
|
|
590
|
+
local function capture_layers(items)
|
|
591
|
+
for _,candidate in ipairs(items) do
|
|
592
|
+
if candidate.isGroup then capture_layers(candidate.layers)
|
|
593
|
+
else
|
|
594
|
+
local cel=candidate:cel(frame)
|
|
595
|
+
if cel~=nil then table.insert(stored,{layer=candidate,image=Image(cel.image),position=Point(cel.position.x,cel.position.y),opacity=cel.opacity,z_index=cel.zIndex,data=cel.data}) end
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
capture_layers(sprite.layers)
|
|
600
|
+
local insertion=target
|
|
601
|
+
if action=="move_frame" and target>frame then insertion=target+1 end
|
|
602
|
+
if insertion<1 or insertion>#sprite.frames+1 then fail("Target frame is outside the insertion range") end
|
|
603
|
+
local inserted=sprite:newEmptyFrame(insertion)
|
|
604
|
+
local inserted_number=inserted.frameNumber
|
|
605
|
+
inserted.duration=duration
|
|
606
|
+
for _,item in ipairs(stored) do local cel=sprite:newCel(item.layer,inserted_number,item.image,item.position) cel.opacity=item.opacity cel.zIndex=item.z_index cel.data=item.data end
|
|
607
|
+
if action=="move_frame" then
|
|
608
|
+
local original=target<=frame and frame+1 or frame
|
|
609
|
+
sprite:deleteFrame(original)
|
|
610
|
+
end
|
|
611
|
+
elseif action=="reverse_range" then app.range.frames={} for index=${input.from ?? 1},${input.to ?? 1} do table.insert(app.range.frames,sprite.frames[index]) end app.command.ReverseFrames()
|
|
612
|
+
else fail("Unsupported animation action") end
|
|
613
|
+
end
|
|
614
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result(sprite_summary(sprite)) sprite:close()
|
|
615
|
+
`);
|
|
616
|
+
return textResponse(result);
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
export async function asepriteRunSafeCommand(config, registry, input) {
|
|
623
|
+
try {
|
|
624
|
+
await prepareMutation(config, registry, input.workspaceId, input.filePath, input, `safe-command-${input.command}`);
|
|
625
|
+
const file = workspacePath(registry, input.workspaceId, input.filePath);
|
|
626
|
+
const result = await runLua(config, registry, input.workspaceId, `
|
|
627
|
+
${openSpriteScript(file.absolute)}
|
|
628
|
+
local command=${luaString(input.command)}
|
|
629
|
+
local layer=${input.layer ? `find_layer(sprite.layers,${luaString(input.layer)})` : "sprite.layers[1]"}
|
|
630
|
+
if command=="flatten" then sprite:flatten()
|
|
631
|
+
elseif command=="clear_cel" then if layer==nil or layer.isGroup then fail("Layer was not found") end local cel=layer:cel(${input.frame ?? 1}) if cel~=nil then cel.image:clear() end
|
|
632
|
+
elseif command=="merge_down" then if layer==nil then fail("Layer was not found") end app.activeLayer=layer app.command.MergeDownLayer()
|
|
633
|
+
elseif command=="background_from_layer" then if layer==nil then fail("Layer was not found") end app.activeLayer=layer app.command.BackgroundFromLayer()
|
|
634
|
+
elseif command=="layer_from_background" then if layer==nil then fail("Layer was not found") end app.activeLayer=layer app.command.LayerFromBackground()
|
|
635
|
+
elseif command=="reverse_frames" then app.range.frames={} for index=${input.from ?? 1},${input.to ?? "#sprite.frames"} do table.insert(app.range.frames,sprite.frames[index]) end app.command.ReverseFrames()
|
|
636
|
+
elseif command=="copy_merged_to_layer" then
|
|
637
|
+
local output=sprite:newLayer() output.name=${luaString(input.outputLayerName ?? "Merged Copy")}
|
|
638
|
+
for frame=1,#sprite.frames do local render=Image(sprite.spec) render:clear() render:drawSprite(sprite,frame,Point(0,0)) sprite:newCel(output,frame,render,Point(0,0)) end
|
|
639
|
+
else fail("Command is not in the safe allowlist") end
|
|
640
|
+
if not sprite:saveAs(${luaString(file.absolute)}) then fail("Unable to save sprite") end emit_result({command=command,summary=sprite_summary(sprite)}) sprite:close()
|
|
641
|
+
`);
|
|
642
|
+
return textResponse(result);
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
return errorResponse(error instanceof Error ? error.message : String(error));
|
|
646
|
+
}
|
|
647
|
+
}
|