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,181 @@
|
|
|
1
|
+
local C = require("live_common")
|
|
2
|
+
local M = {}
|
|
3
|
+
|
|
4
|
+
local function render_frame(sprite, frame_number, composite, layer_name)
|
|
5
|
+
if frame_number < 1 or frame_number > #sprite.frames then C.fail("Frame is outside the sprite") end
|
|
6
|
+
local image = Image(sprite.spec)
|
|
7
|
+
image:clear()
|
|
8
|
+
if composite ~= false then
|
|
9
|
+
image:drawSprite(sprite, frame_number, Point(0, 0))
|
|
10
|
+
else
|
|
11
|
+
local layer = C.find_layer(sprite.layers, layer_name) or app.activeLayer
|
|
12
|
+
if not layer or layer.isGroup or layer.isTilemap then C.fail("A normal drawable layer is required") end
|
|
13
|
+
local cel = layer:cel(frame_number)
|
|
14
|
+
if cel then image:drawImage(cel.image, cel.position) end
|
|
15
|
+
end
|
|
16
|
+
return image
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
local function image_bounds(sprite, image)
|
|
20
|
+
local min_x, min_y, max_x, max_y = sprite.width, sprite.height, -1, -1
|
|
21
|
+
local count = 0
|
|
22
|
+
for y=0,sprite.height-1 do
|
|
23
|
+
for x=0,sprite.width-1 do
|
|
24
|
+
if C.pixel_alpha(sprite, image:getPixel(x, y)) > 0 then
|
|
25
|
+
count = count + 1
|
|
26
|
+
if x < min_x then min_x = x end
|
|
27
|
+
if y < min_y then min_y = y end
|
|
28
|
+
if x > max_x then max_x = x end
|
|
29
|
+
if y > max_y then max_y = y end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
if count == 0 then return { empty=true, pixels=0 } end
|
|
34
|
+
return {
|
|
35
|
+
empty=false,
|
|
36
|
+
pixels=count,
|
|
37
|
+
x=min_x,
|
|
38
|
+
y=min_y,
|
|
39
|
+
width=max_x-min_x+1,
|
|
40
|
+
height=max_y-min_y+1,
|
|
41
|
+
centerX=(min_x+max_x)/2,
|
|
42
|
+
centerY=(min_y+max_y)/2,
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
local function get_sprite_bounds(sprite, params)
|
|
47
|
+
local frame = C.target_frame_number(sprite, params)
|
|
48
|
+
local image = render_frame(sprite, frame, params.composite ~= false, params.layer)
|
|
49
|
+
local bounds = image_bounds(sprite, image)
|
|
50
|
+
bounds.frame = frame
|
|
51
|
+
bounds.composite = params.composite ~= false
|
|
52
|
+
return bounds
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
local function get_color_stats(sprite, params)
|
|
56
|
+
local frame = C.target_frame_number(sprite, params)
|
|
57
|
+
local image = render_frame(sprite, frame, params.composite ~= false, params.layer)
|
|
58
|
+
local counts, opaque, transparent, semitransparent = {}, 0, 0, 0
|
|
59
|
+
for y=0,sprite.height-1 do
|
|
60
|
+
for x=0,sprite.width-1 do
|
|
61
|
+
local color = C.pixel_to_color(sprite, image:getPixel(x, y))
|
|
62
|
+
if color.alpha == 0 then
|
|
63
|
+
transparent = transparent + 1
|
|
64
|
+
else
|
|
65
|
+
opaque = opaque + 1
|
|
66
|
+
if color.alpha < 255 then semitransparent = semitransparent + 1 end
|
|
67
|
+
local hex = C.color_to_hex(color)
|
|
68
|
+
counts[hex] = (counts[hex] or 0) + 1
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
local colors = {}
|
|
73
|
+
for color, count in pairs(counts) do colors[#colors+1] = { color=color, count=count } end
|
|
74
|
+
table.sort(colors, function(a, b)
|
|
75
|
+
if a.count == b.count then return a.color < b.color end
|
|
76
|
+
return a.count > b.count
|
|
77
|
+
end)
|
|
78
|
+
local limit = C.clamp(C.integer(params.limit, 256), 1, 256)
|
|
79
|
+
while #colors > limit do table.remove(colors) end
|
|
80
|
+
local unique = 0
|
|
81
|
+
for _ in pairs(counts) do unique = unique + 1 end
|
|
82
|
+
return {
|
|
83
|
+
frame=frame,
|
|
84
|
+
uniqueColors=unique,
|
|
85
|
+
opaquePixels=opaque,
|
|
86
|
+
transparentPixels=transparent,
|
|
87
|
+
semitransparentPixels=semitransparent,
|
|
88
|
+
colors=colors,
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
local function compare_frames(sprite, params)
|
|
93
|
+
local first = C.clamp(C.integer(params.frameA, 1), 1, #sprite.frames)
|
|
94
|
+
local second = C.clamp(C.integer(params.frameB, math.min(2, #sprite.frames)), 1, #sprite.frames)
|
|
95
|
+
local image_a = render_frame(sprite, first, params.composite ~= false, params.layer)
|
|
96
|
+
local image_b = render_frame(sprite, second, params.composite ~= false, params.layer)
|
|
97
|
+
local changed, min_x, min_y, max_x, max_y = 0, sprite.width, sprite.height, -1, -1
|
|
98
|
+
for y=0,sprite.height-1 do
|
|
99
|
+
for x=0,sprite.width-1 do
|
|
100
|
+
if image_a:getPixel(x, y) ~= image_b:getPixel(x, y) then
|
|
101
|
+
changed = changed + 1
|
|
102
|
+
if x < min_x then min_x = x end
|
|
103
|
+
if y < min_y then min_y = y end
|
|
104
|
+
if x > max_x then max_x = x end
|
|
105
|
+
if y > max_y then max_y = y end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
local total = sprite.width * sprite.height
|
|
110
|
+
return {
|
|
111
|
+
frameA=first,
|
|
112
|
+
frameB=second,
|
|
113
|
+
exact=changed == 0,
|
|
114
|
+
changedPixels=changed,
|
|
115
|
+
matchPercent=total == 0 and 100 or ((total-changed)/total)*100,
|
|
116
|
+
differenceBounds=changed == 0 and nil or { x=min_x, y=min_y, width=max_x-min_x+1, height=max_y-min_y+1 },
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
local function find_tag(sprite, name)
|
|
121
|
+
if name == nil then return nil end
|
|
122
|
+
for _, tag in ipairs(sprite.tags) do if tag.name == name then return tag end end
|
|
123
|
+
return nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
local function validate_animation(sprite, params)
|
|
127
|
+
local tag = find_tag(sprite, params.tag)
|
|
128
|
+
if params.tag and not tag then C.fail("Tag was not found") end
|
|
129
|
+
local from = tag and tag.fromFrame.frameNumber or C.clamp(C.integer(params.from, 1), 1, #sprite.frames)
|
|
130
|
+
local to = tag and tag.toFrame.frameNumber or C.clamp(C.integer(params.to, #sprite.frames), from, #sprite.frames)
|
|
131
|
+
local frames, issues = {}, {}
|
|
132
|
+
local previous_image = nil
|
|
133
|
+
local previous_bounds = nil
|
|
134
|
+
for frame=from,to do
|
|
135
|
+
local image = render_frame(sprite, frame, true)
|
|
136
|
+
local bounds = image_bounds(sprite, image)
|
|
137
|
+
local duration = math.floor(sprite.frames[frame].duration * 1000 + 0.5)
|
|
138
|
+
local duplicate = false
|
|
139
|
+
if previous_image then
|
|
140
|
+
duplicate = true
|
|
141
|
+
for y=0,sprite.height-1 do
|
|
142
|
+
for x=0,sprite.width-1 do
|
|
143
|
+
if image:getPixel(x, y) ~= previous_image:getPixel(x, y) then duplicate = false break end
|
|
144
|
+
end
|
|
145
|
+
if not duplicate then break end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
local movement = nil
|
|
149
|
+
if previous_bounds and not previous_bounds.empty and not bounds.empty then
|
|
150
|
+
movement = {
|
|
151
|
+
dx=bounds.centerX-previous_bounds.centerX,
|
|
152
|
+
dy=bounds.centerY-previous_bounds.centerY,
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
frames[#frames+1] = { frame=frame, durationMs=duration, bounds=bounds, duplicatePrevious=duplicate, movement=movement }
|
|
156
|
+
if bounds.empty then issues[#issues+1] = { frame=frame, type="empty_frame" } end
|
|
157
|
+
if duplicate then issues[#issues+1] = { frame=frame, type="duplicate_previous" } end
|
|
158
|
+
if duration < 16 or duration > 2000 then issues[#issues+1] = { frame=frame, type="duration_outlier", durationMs=duration } end
|
|
159
|
+
previous_image, previous_bounds = image, bounds
|
|
160
|
+
end
|
|
161
|
+
local loop = compare_frames(sprite, { frameA=from, frameB=to, composite=true })
|
|
162
|
+
return {
|
|
163
|
+
tag=tag and tag.name or nil,
|
|
164
|
+
from=from,
|
|
165
|
+
to=to,
|
|
166
|
+
frameCount=to-from+1,
|
|
167
|
+
frames=frames,
|
|
168
|
+
issues=issues,
|
|
169
|
+
loopEndpointDifference=loop,
|
|
170
|
+
valid=#issues == 0,
|
|
171
|
+
}
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
M.handlers = {
|
|
175
|
+
get_sprite_bounds=get_sprite_bounds,
|
|
176
|
+
get_color_stats=get_color_stats,
|
|
177
|
+
compare_frames=compare_frames,
|
|
178
|
+
validate_animation=validate_animation,
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return M
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
local C = require("live_common")
|
|
2
|
+
local M = {}
|
|
3
|
+
|
|
4
|
+
local function set_frame_range_duration(sprite, params)
|
|
5
|
+
local from = C.clamp(C.integer(params.from, 1), 1, #sprite.frames)
|
|
6
|
+
local to = C.clamp(C.integer(params.to, from), from, #sprite.frames)
|
|
7
|
+
local duration_ms = C.clamp(C.integer(params.durationMs, 100), 1, 60000)
|
|
8
|
+
app.transaction("Auvrynt Live Frame Durations", function()
|
|
9
|
+
for frame=from,to do sprite.frames[frame].duration = duration_ms / 1000 end
|
|
10
|
+
end)
|
|
11
|
+
return { from=from, to=to, durationMs=duration_ms }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
local function duplicate_frame(sprite, params)
|
|
15
|
+
local source = C.target_frame_number(sprite, params)
|
|
16
|
+
local created
|
|
17
|
+
app.transaction("Auvrynt Live Duplicate Frame", function()
|
|
18
|
+
sprite:newFrame(source)
|
|
19
|
+
created = sprite.frames[source + 1]
|
|
20
|
+
if params.durationMs ~= nil then created.duration = C.clamp(C.integer(params.durationMs, 100), 1, 60000) / 1000 end
|
|
21
|
+
end)
|
|
22
|
+
app.activeFrame = created
|
|
23
|
+
return { source=source, frame=created.frameNumber, durationMs=math.floor(created.duration * 1000 + 0.5) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
local function reverse_frames(sprite, params)
|
|
27
|
+
local from = C.clamp(C.integer(params.from, 1), 1, #sprite.frames)
|
|
28
|
+
local to = C.clamp(C.integer(params.to, #sprite.frames), from, #sprite.frames)
|
|
29
|
+
local frames = {}
|
|
30
|
+
for frame=from,to do frames[#frames+1] = sprite.frames[frame] end
|
|
31
|
+
app.activeSprite = sprite
|
|
32
|
+
app.range.frames = frames
|
|
33
|
+
app.command.ReverseFrames()
|
|
34
|
+
return { from=from, to=to, count=to-from+1 }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
local function shift_cel(sprite, params)
|
|
38
|
+
local layer, frame_number = C.active_target(sprite, params)
|
|
39
|
+
local dx, dy = C.integer(params.dx, 0), C.integer(params.dy, 0)
|
|
40
|
+
local cel = layer:cel(frame_number)
|
|
41
|
+
if not cel then C.fail("Cel does not exist") end
|
|
42
|
+
app.transaction("Auvrynt Live Shift Cel", function()
|
|
43
|
+
if params.wrap == true then
|
|
44
|
+
cel = C.get_canvas_cel(sprite, layer, frame_number, true)
|
|
45
|
+
local source = Image(cel.image)
|
|
46
|
+
local transparent = C.color_to_pixel(sprite, Color{r=0,g=0,b=0,a=0})
|
|
47
|
+
cel.image:clear(transparent)
|
|
48
|
+
for y=0,sprite.height-1 do
|
|
49
|
+
for x=0,sprite.width-1 do
|
|
50
|
+
local nx = (x + dx) % sprite.width
|
|
51
|
+
local ny = (y + dy) % sprite.height
|
|
52
|
+
cel.image:drawPixel(nx, ny, source:getPixel(x, y))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
cel.position = Point(cel.position.x + dx, cel.position.y + dy)
|
|
57
|
+
end
|
|
58
|
+
end)
|
|
59
|
+
return { layer=layer.name, frame=frame_number, x=cel.position.x, y=cel.position.y, dx=dx, dy=dy, wrap=params.wrap == true }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
local function flip_sprite(sprite, params)
|
|
63
|
+
local orientation = params.orientation == "vertical" and "vertical" or "horizontal"
|
|
64
|
+
app.activeSprite = sprite
|
|
65
|
+
app.command.Flip { orientation=orientation }
|
|
66
|
+
return { orientation=orientation, width=sprite.width, height=sprite.height }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
local function rotate_sprite(sprite, params)
|
|
70
|
+
local angle = C.integer(params.angle, 90)
|
|
71
|
+
if angle ~= 90 and angle ~= 180 and angle ~= 270 and angle ~= -90 then C.fail("angle must be 90, 180, 270, or -90") end
|
|
72
|
+
app.activeSprite = sprite
|
|
73
|
+
app.command.Rotate { angle=angle, ui=false }
|
|
74
|
+
return { angle=angle, width=sprite.width, height=sprite.height }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
local function resolve_open_sprite(params, prefix)
|
|
78
|
+
local id = params[prefix .. "Id"]
|
|
79
|
+
local filename = params[prefix .. "Filename"]
|
|
80
|
+
for _, sprite in ipairs(app.sprites) do
|
|
81
|
+
if id ~= nil and tostring(sprite.id) == tostring(id) then return sprite end
|
|
82
|
+
if filename ~= nil and sprite.filename == filename then return sprite end
|
|
83
|
+
end
|
|
84
|
+
C.fail(prefix .. " sprite was not found among open documents")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
local function copy_between_sprites(_, params)
|
|
88
|
+
local source = resolve_open_sprite(params, "source")
|
|
89
|
+
local target = resolve_open_sprite(params, "target")
|
|
90
|
+
local source_layer = C.find_layer(source.layers, params.sourceLayer)
|
|
91
|
+
if not source_layer or source_layer.isGroup or source_layer.isTilemap then C.fail("Source drawable layer was not found") end
|
|
92
|
+
local source_frame = C.clamp(C.integer(params.sourceFrame, 1), 1, #source.frames)
|
|
93
|
+
local source_cel = source_layer:cel(source_frame)
|
|
94
|
+
if not source_cel then C.fail("Source cel does not exist") end
|
|
95
|
+
local target_layer = params.targetLayer and C.find_layer(target.layers, params.targetLayer) or nil
|
|
96
|
+
if not target_layer then
|
|
97
|
+
target_layer = target:newLayer()
|
|
98
|
+
target_layer.name = tostring(params.targetLayer or source_layer.name)
|
|
99
|
+
end
|
|
100
|
+
if target_layer.isGroup or target_layer.isTilemap then C.fail("Target must be a normal drawable layer") end
|
|
101
|
+
local target_frame = C.clamp(C.integer(params.targetFrame, 1), 1, #target.frames)
|
|
102
|
+
local created
|
|
103
|
+
app.transaction("Auvrynt Live Copy Between Sprites", function()
|
|
104
|
+
local existing = target_layer:cel(target_frame)
|
|
105
|
+
if existing then target:deleteCel(existing) end
|
|
106
|
+
created = target:newCel(
|
|
107
|
+
target_layer,
|
|
108
|
+
target_frame,
|
|
109
|
+
source_cel.image,
|
|
110
|
+
Point(source_cel.position.x + C.integer(params.offsetX, 0), source_cel.position.y + C.integer(params.offsetY, 0))
|
|
111
|
+
)
|
|
112
|
+
created.opacity = source_cel.opacity
|
|
113
|
+
created.zIndex = source_cel.zIndex
|
|
114
|
+
end)
|
|
115
|
+
app.activeSprite, app.activeLayer, app.activeFrame = target, target_layer, target.frames[target_frame]
|
|
116
|
+
return {
|
|
117
|
+
sourceId=tostring(source.id), targetId=tostring(target.id),
|
|
118
|
+
sourceLayer=source_layer.name, targetLayer=target_layer.name,
|
|
119
|
+
sourceFrame=source_frame, targetFrame=target_frame,
|
|
120
|
+
x=created.position.x, y=created.position.y,
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
M.handlers = {
|
|
125
|
+
set_frame_range_duration=set_frame_range_duration,
|
|
126
|
+
duplicate_frame=duplicate_frame,
|
|
127
|
+
reverse_frames=reverse_frames,
|
|
128
|
+
shift_cel=shift_cel,
|
|
129
|
+
flip_sprite=flip_sprite,
|
|
130
|
+
rotate_sprite=rotate_sprite,
|
|
131
|
+
copy_between_sprites=copy_between_sprites,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return M
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
local M = {}
|
|
2
|
+
local handlers = {}
|
|
3
|
+
|
|
4
|
+
for _, module_name in ipairs({ "live_drawing", "live_structure", "live_palette_template", "live_selection", "live_animation", "live_analysis", "live_document", "live_effects" }) do
|
|
5
|
+
local module = require(module_name)
|
|
6
|
+
for name, handler in pairs(module.handlers) do handlers[name] = handler end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
function M.run(sprite, request)
|
|
10
|
+
local command = request.liveCommand
|
|
11
|
+
if type(command) ~= "string" or command == "" then error("liveCommand is required", 0) end
|
|
12
|
+
local handler = handlers[command]
|
|
13
|
+
if not handler then error("Unsupported live command: " .. command, 0) end
|
|
14
|
+
return handler(sprite, request.arguments or {})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
function M.names()
|
|
18
|
+
local result = {}
|
|
19
|
+
for name in pairs(handlers) do result[#result+1] = name end
|
|
20
|
+
table.sort(result)
|
|
21
|
+
return result
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
return M
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
local M = {}
|
|
2
|
+
local pc = app.pixelColor
|
|
3
|
+
|
|
4
|
+
function M.fail(message) error(message, 0) end
|
|
5
|
+
function M.clamp(value, minimum, maximum) return math.max(minimum, math.min(maximum, value)) end
|
|
6
|
+
function M.integer(value, fallback) return math.floor(tonumber(value) or fallback or 0) end
|
|
7
|
+
function M.sequence_length(value)
|
|
8
|
+
if value == nil then return nil end
|
|
9
|
+
local ok, count = pcall(function() return #value end)
|
|
10
|
+
return ok and count or nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
function M.color_from_hex(value, fallback)
|
|
14
|
+
if type(value) ~= "string" then return fallback or Color() end
|
|
15
|
+
local hex = value:gsub("^#", "")
|
|
16
|
+
if #hex ~= 6 and #hex ~= 8 then M.fail("Colors must use #RRGGBB or #RRGGBBAA") end
|
|
17
|
+
local r, g, b = tonumber(hex:sub(1, 2), 16), tonumber(hex:sub(3, 4), 16), tonumber(hex:sub(5, 6), 16)
|
|
18
|
+
local a = #hex == 8 and tonumber(hex:sub(7, 8), 16) or 255
|
|
19
|
+
if not r or not g or not b or not a then M.fail("Invalid hexadecimal color") end
|
|
20
|
+
return Color { r=r, g=g, b=b, a=a }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
function M.color_to_hex(color)
|
|
24
|
+
return string.format("#%02X%02X%02X%02X", color.red, color.green, color.blue, color.alpha)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
function M.pixel_to_color(sprite, pixel)
|
|
28
|
+
if sprite.colorMode == ColorMode.RGB then
|
|
29
|
+
return Color { r=pc.rgbaR(pixel), g=pc.rgbaG(pixel), b=pc.rgbaB(pixel), a=pc.rgbaA(pixel) }
|
|
30
|
+
elseif sprite.colorMode == ColorMode.GRAY then
|
|
31
|
+
local value = pc.grayaV(pixel)
|
|
32
|
+
return Color { r=value, g=value, b=value, a=pc.grayaA(pixel) }
|
|
33
|
+
end
|
|
34
|
+
local palette = sprite.palettes[1]
|
|
35
|
+
local color = palette:getColor(pixel)
|
|
36
|
+
return Color { r=color.red, g=color.green, b=color.blue, a=pixel == sprite.transparentColor and 0 or color.alpha }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
function M.color_to_pixel(sprite, color)
|
|
40
|
+
if sprite.colorMode == ColorMode.RGB then return pc.rgba(color.red, color.green, color.blue, color.alpha) end
|
|
41
|
+
if sprite.colorMode == ColorMode.GRAY then
|
|
42
|
+
local gray = math.floor((color.red*299 + color.green*587 + color.blue*114)/1000)
|
|
43
|
+
return pc.graya(gray, color.alpha)
|
|
44
|
+
end
|
|
45
|
+
if color.alpha == 0 then return sprite.transparentColor end
|
|
46
|
+
local palette, best, distance = sprite.palettes[1], 0, math.huge
|
|
47
|
+
for index=0,#palette-1 do
|
|
48
|
+
local candidate = palette:getColor(index)
|
|
49
|
+
local dr, dg, db, da = candidate.red-color.red, candidate.green-color.green, candidate.blue-color.blue, candidate.alpha-color.alpha
|
|
50
|
+
local current = dr*dr + dg*dg + db*db + da*da
|
|
51
|
+
if current < distance then best, distance = index, current end
|
|
52
|
+
end
|
|
53
|
+
return best
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
function M.pixel_alpha(sprite, pixel)
|
|
57
|
+
if sprite.colorMode == ColorMode.RGB then return pc.rgbaA(pixel) end
|
|
58
|
+
if sprite.colorMode == ColorMode.GRAY then return pc.grayaA(pixel) end
|
|
59
|
+
if pixel == sprite.transparentColor then return 0 end
|
|
60
|
+
return sprite.palettes[1]:getColor(pixel).alpha
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
function M.find_layer(items, name_or_id)
|
|
64
|
+
if name_or_id == nil then return nil end
|
|
65
|
+
for _, layer in ipairs(items) do
|
|
66
|
+
if layer.name == name_or_id or tostring(layer.id) == tostring(name_or_id) then return layer end
|
|
67
|
+
if layer.isGroup then
|
|
68
|
+
local nested = M.find_layer(layer.layers, name_or_id)
|
|
69
|
+
if nested then return nested end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
return nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
function M.target_layer(sprite, params)
|
|
76
|
+
local layer = params.layer and M.find_layer(sprite.layers, params.layer) or app.activeLayer or sprite.layers[1]
|
|
77
|
+
if not layer then M.fail("Layer was not found") end
|
|
78
|
+
if layer.isGroup or layer.isTilemap then M.fail("A normal drawable layer is required") end
|
|
79
|
+
return layer
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
function M.target_frame_number(sprite, params)
|
|
83
|
+
local number = M.integer(params.frame, app.activeFrame and app.activeFrame.frameNumber or 1)
|
|
84
|
+
if number < 1 or number > #sprite.frames then M.fail("Frame is outside the sprite") end
|
|
85
|
+
return number
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
function M.get_canvas_cel(sprite, layer, frame_number, create)
|
|
89
|
+
local cel = layer:cel(frame_number)
|
|
90
|
+
if not cel and create then
|
|
91
|
+
local image = Image(sprite.spec)
|
|
92
|
+
image:clear()
|
|
93
|
+
cel = sprite:newCel(layer, frame_number, image, Point(0, 0))
|
|
94
|
+
end
|
|
95
|
+
if cel and create and (cel.position.x ~= 0 or cel.position.y ~= 0 or cel.image.width ~= sprite.width or cel.image.height ~= sprite.height) then
|
|
96
|
+
local image = Image(sprite.spec)
|
|
97
|
+
image:clear()
|
|
98
|
+
image:drawImage(cel.image, cel.position)
|
|
99
|
+
cel.image = image
|
|
100
|
+
cel.position = Point(0, 0)
|
|
101
|
+
end
|
|
102
|
+
return cel
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
function M.selection_allows(sprite, x, y)
|
|
106
|
+
local selection = sprite.selection
|
|
107
|
+
return selection == nil or selection.isEmpty or selection:contains(Point(x, y))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
function M.active_target(sprite, params)
|
|
111
|
+
local layer, frame_number = M.target_layer(sprite, params), M.target_frame_number(sprite, params)
|
|
112
|
+
app.activeSprite, app.activeLayer, app.activeFrame = sprite, layer, sprite.frames[frame_number]
|
|
113
|
+
return layer, frame_number
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
function M.read_canvas(sprite, params)
|
|
117
|
+
local frame_number = M.target_frame_number(sprite, params)
|
|
118
|
+
local image = Image(sprite.spec)
|
|
119
|
+
image:clear()
|
|
120
|
+
if params.composite == true then
|
|
121
|
+
image:drawSprite(sprite, frame_number, Point(0, 0))
|
|
122
|
+
else
|
|
123
|
+
local layer = M.target_layer(sprite, params)
|
|
124
|
+
local cel = layer:cel(frame_number)
|
|
125
|
+
if cel then image:drawImage(cel.image, cel.position) end
|
|
126
|
+
end
|
|
127
|
+
return image, frame_number
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
return M
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
local C = require("live_common")
|
|
2
|
+
local M = {}
|
|
3
|
+
|
|
4
|
+
local function resize_sprite(sprite, params)
|
|
5
|
+
local width = C.clamp(C.integer(params.width, sprite.width), 1, 8192)
|
|
6
|
+
local height = C.clamp(C.integer(params.height, sprite.height), 1, 8192)
|
|
7
|
+
app.activeSprite = sprite
|
|
8
|
+
sprite:resize(width, height)
|
|
9
|
+
return { width=sprite.width, height=sprite.height }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
local function crop_sprite(sprite, params)
|
|
13
|
+
local x = C.integer(params.x, 0)
|
|
14
|
+
local y = C.integer(params.y, 0)
|
|
15
|
+
local width = C.integer(params.width, sprite.width)
|
|
16
|
+
local height = C.integer(params.height, sprite.height)
|
|
17
|
+
if width < 1 or height < 1 then C.fail("width and height must be positive") end
|
|
18
|
+
sprite:crop(Rectangle(x, y, width, height))
|
|
19
|
+
return { width=sprite.width, height=sprite.height, source={x=x,y=y,width=width,height=height} }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
local function flatten_sprite(sprite, _)
|
|
23
|
+
sprite:flatten()
|
|
24
|
+
app.activeLayer = sprite.layers[1]
|
|
25
|
+
return { layers=#sprite.layers, activeLayer=sprite.layers[1].name }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
local function set_grid(sprite, params)
|
|
29
|
+
local x = C.integer(params.x, 0)
|
|
30
|
+
local y = C.integer(params.y, 0)
|
|
31
|
+
local width = C.clamp(C.integer(params.width, 8), 1, 8192)
|
|
32
|
+
local height = C.clamp(C.integer(params.height, 8), 1, 8192)
|
|
33
|
+
sprite.gridBounds = Rectangle(x, y, width, height)
|
|
34
|
+
return { x=x, y=y, width=width, height=height }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
local function create_tileset_template(_, params)
|
|
38
|
+
local tile_size = C.clamp(C.integer(params.tileSize, 16), 1, 256)
|
|
39
|
+
local columns = C.clamp(C.integer(params.columns, 8), 1, 128)
|
|
40
|
+
local rows = C.clamp(C.integer(params.rows, 8), 1, 128)
|
|
41
|
+
local width, height = tile_size * columns, tile_size * rows
|
|
42
|
+
if width > 8192 or height > 8192 then C.fail("Tileset template exceeds Aseprite's 8192px bridge limit") end
|
|
43
|
+
local sprite = Sprite(width, height, ColorMode.RGB)
|
|
44
|
+
app.activeSprite = sprite
|
|
45
|
+
app.transaction("Auvrynt Tileset Template", function()
|
|
46
|
+
sprite.layers[1].name = "tiles"
|
|
47
|
+
sprite.gridBounds = Rectangle(0, 0, tile_size, tile_size)
|
|
48
|
+
local grid = sprite:newLayer()
|
|
49
|
+
grid.name = "grid-guide"
|
|
50
|
+
grid.opacity = C.clamp(C.integer(params.gridOpacity, 64), 0, 255)
|
|
51
|
+
local image = Image(sprite.spec)
|
|
52
|
+
image:clear()
|
|
53
|
+
local color = C.color_to_pixel(sprite, C.color_from_hex(params.gridColor or "#FFFFFFFF"))
|
|
54
|
+
for column=1,columns-1 do
|
|
55
|
+
local x = column * tile_size
|
|
56
|
+
for y=0,height-1 do image:drawPixel(x, y, color) end
|
|
57
|
+
end
|
|
58
|
+
for row=1,rows-1 do
|
|
59
|
+
local y = row * tile_size
|
|
60
|
+
for x=0,width-1 do image:drawPixel(x, y, color) end
|
|
61
|
+
end
|
|
62
|
+
sprite:newCel(grid, 1, image, Point(0, 0))
|
|
63
|
+
end)
|
|
64
|
+
return {
|
|
65
|
+
id=tostring(sprite.id), tileSize=tile_size, columns=columns, rows=rows,
|
|
66
|
+
width=width, height=height, layers={"tiles","grid-guide"},
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
M.handlers = {
|
|
71
|
+
resize_sprite=resize_sprite,
|
|
72
|
+
crop_sprite=crop_sprite,
|
|
73
|
+
flatten_sprite=flatten_sprite,
|
|
74
|
+
set_grid=set_grid,
|
|
75
|
+
create_tileset_template=create_tileset_template,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return M
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
local C = require("live_common")
|
|
2
|
+
local M = {}
|
|
3
|
+
|
|
4
|
+
local function get_pixel(sprite, params)
|
|
5
|
+
local x, y = C.integer(params.x, -1), C.integer(params.y, -1)
|
|
6
|
+
if x < 0 or y < 0 or x >= sprite.width or y >= sprite.height then C.fail("Pixel is outside the sprite") end
|
|
7
|
+
local image, frame_number = C.read_canvas(sprite, params)
|
|
8
|
+
local color = C.pixel_to_color(sprite, image:getPixel(x, y))
|
|
9
|
+
return { x=x, y=y, frame=frame_number, color=C.color_to_hex(color), r=color.red, g=color.green, b=color.blue, a=color.alpha }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
local function get_image_data(sprite, params)
|
|
13
|
+
local image, frame_number = C.read_canvas(sprite, params)
|
|
14
|
+
local region = params.region or {}
|
|
15
|
+
local x = C.clamp(C.integer(region.x, 0), 0, sprite.width - 1)
|
|
16
|
+
local y = C.clamp(C.integer(region.y, 0), 0, sprite.height - 1)
|
|
17
|
+
local width = C.clamp(C.integer(region.width, sprite.width - x), 1, sprite.width - x)
|
|
18
|
+
local height = C.clamp(C.integer(region.height, sprite.height - y), 1, sprite.height - y)
|
|
19
|
+
if width * height > 16384 then C.fail("Live image readback is limited to 16384 pixels") end
|
|
20
|
+
local rows = {}
|
|
21
|
+
for row=0,height-1 do
|
|
22
|
+
local output = {}
|
|
23
|
+
for column=0,width-1 do output[column+1] = C.color_to_hex(C.pixel_to_color(sprite, image:getPixel(x+column, y+row))) end
|
|
24
|
+
rows[row+1] = output
|
|
25
|
+
end
|
|
26
|
+
return { frame=frame_number, x=x, y=y, width=width, height=height, composite=params.composite == true, rows=rows }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
local function draw_tool(sprite, params, tool, point_count)
|
|
30
|
+
local layer, frame_number = C.active_target(sprite, params)
|
|
31
|
+
local points = { Point(C.integer(params.x, 0), C.integer(params.y, 0)) }
|
|
32
|
+
if point_count == 2 then
|
|
33
|
+
local x2 = params.x2 ~= nil and C.integer(params.x2, 0) or C.integer(params.x, 0) + C.integer(params.width, 1) - 1
|
|
34
|
+
local y2 = params.y2 ~= nil and C.integer(params.y2, 0) or C.integer(params.y, 0) + C.integer(params.height, 1) - 1
|
|
35
|
+
points[2] = Point(x2, y2)
|
|
36
|
+
end
|
|
37
|
+
app.transaction("Auvrynt Live " .. tool, function()
|
|
38
|
+
app.useTool {
|
|
39
|
+
tool=tool,
|
|
40
|
+
color=C.color_from_hex(params.color, app.fgColor),
|
|
41
|
+
opacity=C.clamp(C.integer(params.opacity, 255), 0, 255),
|
|
42
|
+
brush=Brush(C.clamp(C.integer(params.brushSize, 1), 1, 256)),
|
|
43
|
+
points=points,
|
|
44
|
+
layer=layer,
|
|
45
|
+
frame=sprite.frames[frame_number],
|
|
46
|
+
}
|
|
47
|
+
end)
|
|
48
|
+
return { tool=tool, frame=frame_number, layer=layer.name }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
local function clear_image(sprite, params)
|
|
52
|
+
local layer, frame_number = C.active_target(sprite, params)
|
|
53
|
+
local fill = params.color and C.color_to_pixel(sprite, C.color_from_hex(params.color)) or C.color_to_pixel(sprite, Color{r=0,g=0,b=0,a=0})
|
|
54
|
+
local changed = 0
|
|
55
|
+
app.transaction("Auvrynt Live Clear", function()
|
|
56
|
+
local cel = C.get_canvas_cel(sprite, layer, frame_number, true)
|
|
57
|
+
for y=0,sprite.height-1 do
|
|
58
|
+
for x=0,sprite.width-1 do
|
|
59
|
+
if C.selection_allows(sprite, x, y) then cel.image:drawPixel(x, y, fill) changed = changed + 1 end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end)
|
|
63
|
+
return { changed=changed, frame=frame_number, layer=layer.name }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
local function replace_color(sprite, params)
|
|
67
|
+
if type(params.fromColor) ~= "string" or type(params.toColor) ~= "string" then C.fail("fromColor and toColor are required") end
|
|
68
|
+
local layer, frame_number = C.active_target(sprite, params)
|
|
69
|
+
local from_pixel = C.color_to_pixel(sprite, C.color_from_hex(params.fromColor))
|
|
70
|
+
local to_pixel = C.color_to_pixel(sprite, C.color_from_hex(params.toColor))
|
|
71
|
+
local changed = 0
|
|
72
|
+
app.transaction("Auvrynt Live Replace Color", function()
|
|
73
|
+
local cel = C.get_canvas_cel(sprite, layer, frame_number, true)
|
|
74
|
+
for y=0,sprite.height-1 do
|
|
75
|
+
for x=0,sprite.width-1 do
|
|
76
|
+
if C.selection_allows(sprite, x, y) and cel.image:getPixel(x, y) == from_pixel then
|
|
77
|
+
cel.image:drawPixel(x, y, to_pixel)
|
|
78
|
+
changed = changed + 1
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end)
|
|
83
|
+
return { changed=changed, frame=frame_number, layer=layer.name }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
local function outline(sprite, params)
|
|
87
|
+
if type(params.color) ~= "string" then C.fail("color is required") end
|
|
88
|
+
local layer, frame_number = C.active_target(sprite, params)
|
|
89
|
+
local outline_pixel = C.color_to_pixel(sprite, C.color_from_hex(params.color))
|
|
90
|
+
local neighbors = params.diagonal == true
|
|
91
|
+
and { {-1,-1},{0,-1},{1,-1},{-1,0},{1,0},{-1,1},{0,1},{1,1} }
|
|
92
|
+
or { {0,-1},{-1,0},{1,0},{0,1} }
|
|
93
|
+
local changed = 0
|
|
94
|
+
app.transaction("Auvrynt Live Outline", function()
|
|
95
|
+
local cel = C.get_canvas_cel(sprite, layer, frame_number, true)
|
|
96
|
+
local source = Image(cel.image)
|
|
97
|
+
for y=0,sprite.height-1 do
|
|
98
|
+
for x=0,sprite.width-1 do
|
|
99
|
+
if C.selection_allows(sprite, x, y) and C.pixel_alpha(sprite, source:getPixel(x, y)) == 0 then
|
|
100
|
+
local adjacent = false
|
|
101
|
+
for _, offset in ipairs(neighbors) do
|
|
102
|
+
local nx, ny = x + offset[1], y + offset[2]
|
|
103
|
+
if nx >= 0 and ny >= 0 and nx < sprite.width and ny < sprite.height and C.pixel_alpha(sprite, source:getPixel(nx, ny)) > 0 then adjacent = true break end
|
|
104
|
+
end
|
|
105
|
+
if adjacent then cel.image:drawPixel(x, y, outline_pixel) changed = changed + 1 end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end)
|
|
110
|
+
return { changed=changed, frame=frame_number, layer=layer.name, diagonal=params.diagonal == true }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
M.handlers = {
|
|
114
|
+
get_pixel=get_pixel,
|
|
115
|
+
get_image_data=get_image_data,
|
|
116
|
+
draw_line=function(sprite, params) return draw_tool(sprite, params, "line", 2) end,
|
|
117
|
+
draw_rect=function(sprite, params) return draw_tool(sprite, params, params.filled == false and "rectangle" or "filled_rectangle", 2) end,
|
|
118
|
+
draw_ellipse=function(sprite, params) return draw_tool(sprite, params, params.filled == false and "ellipse" or "filled_ellipse", 2) end,
|
|
119
|
+
flood_fill=function(sprite, params) return draw_tool(sprite, params, "paint_bucket", 1) end,
|
|
120
|
+
clear_image=clear_image,
|
|
121
|
+
replace_color=replace_color,
|
|
122
|
+
outline=outline,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return M
|