diff --git a/.gitignore b/.gitignore
index ce5f5e90d..65a97ce7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -142,6 +142,8 @@ spine-cocos2dx/example-v4/cocos2dx.zip
spine-ts/spine-core/dist
spine-ts/spine-canvas/dist
+spine-ts/spine-construct3/dist
+spine-ts/spine-construct3-lib/dist
spine-ts/spine-webgl/dist
spine-ts/spine-player/dist
spine-ts/spine-webcomponents/dist
diff --git a/spine-ts/index.html b/spine-ts/index.html
index 4b101afe3..e09b41fdc 100644
--- a/spine-ts/index.html
+++ b/spine-ts/index.html
@@ -204,6 +204,10 @@
Dispose
GUI
+ Construct 3
+
diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json
index 203544bc9..5bc53a59e 100644
--- a/spine-ts/package-lock.json
+++ b/spine-ts/package-lock.json
@@ -11,13 +11,15 @@
"workspaces": [
"spine-core",
"spine-canvas",
+ "spine-canvaskit",
+ "spine-construct3",
+ "spine-construct3-lib",
"spine-phaser-v3",
"spine-phaser-v4",
"spine-player",
"spine-threejs",
"spine-pixi-v7",
"spine-pixi-v8",
- "spine-canvaskit",
"spine-webgl",
"spine-webcomponents"
],
@@ -25,10 +27,12 @@
"@biomejs/biome": "^2.1.1",
"@types/offscreencanvas": "^2019.7.3",
"alive-server": "^1.3.0",
+ "chokidar-cli": "^3.0.0",
"concurrently": "^9.2.0",
"copyfiles": "^2.4.1",
"esbuild": "^0.25.6",
"rimraf": "^6.0.1",
+ "tsc-watch": "^7.1.1",
"typescript": "^5.8.3",
"typescript-formatter": "^7.2.2"
}
@@ -646,6 +650,14 @@
"resolved": "spine-canvaskit",
"link": true
},
+ "node_modules/@esotericsoftware/spine-construct3": {
+ "resolved": "spine-construct3",
+ "link": true
+ },
+ "node_modules/@esotericsoftware/spine-construct3-lib": {
+ "resolved": "spine-construct3-lib",
+ "link": true
+ },
"node_modules/@esotericsoftware/spine-core": {
"resolved": "spine-core",
"link": true
@@ -1068,63 +1080,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/alive-server/node_modules/anymatch": {
- "version": "3.1.3",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/alive-server/node_modules/binary-extensions": {
- "version": "2.3.0",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/alive-server/node_modules/braces": {
- "version": "3.0.3",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/alive-server/node_modules/chokidar": {
- "version": "3.6.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
"node_modules/alive-server/node_modules/event-stream": {
"version": "4.0.1",
"dev": true,
@@ -1139,28 +1094,6 @@
"through": "^2.3.8"
}
},
- "node_modules/alive-server/node_modules/fill-range": {
- "version": "7.1.1",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/alive-server/node_modules/glob-parent": {
- "version": "5.1.2",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/alive-server/node_modules/http-auth": {
"version": "4.2.0",
"dev": true,
@@ -1175,41 +1108,11 @@
"node": ">=8"
}
},
- "node_modules/alive-server/node_modules/is-binary-path": {
- "version": "2.1.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/alive-server/node_modules/is-number": {
- "version": "7.0.0",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.12.0"
- }
- },
"node_modules/alive-server/node_modules/map-stream": {
"version": "0.0.7",
"dev": true,
"license": "MIT"
},
- "node_modules/alive-server/node_modules/readdirp": {
- "version": "3.6.0",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
"node_modules/alive-server/node_modules/split": {
"version": "1.0.1",
"dev": true,
@@ -1230,17 +1133,6 @@
"through": "~2.3.4"
}
},
- "node_modules/alive-server/node_modules/to-regex-range": {
- "version": "5.0.1",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/alive-server/node_modules/uuid": {
"version": "8.3.2",
"dev": true,
@@ -1271,6 +1163,20 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/apache-crypt": {
"version": "1.2.6",
"dev": true,
@@ -1316,6 +1222,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"dev": true,
@@ -1325,6 +1244,19 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"license": "MIT",
@@ -1352,6 +1284,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/canvaskit-wasm": {
"version": "0.39.1",
"license": "BSD-3-Clause",
@@ -1385,6 +1327,199 @@
"node": ">=8"
}
},
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar-cli": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar-cli/-/chokidar-cli-3.0.0.tgz",
+ "integrity": "sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "lodash.debounce": "^4.0.8",
+ "lodash.throttle": "^4.1.1",
+ "yargs": "^13.3.0"
+ },
+ "bin": {
+ "chokidar": "index.js"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/ansi-regex": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
+ "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/cliui": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^3.1.0",
+ "strip-ansi": "^5.2.0",
+ "wrap-ansi": "^5.1.0"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/chokidar-cli/node_modules/emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/chokidar-cli/node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/wrap-ansi": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+ "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.0",
+ "string-width": "^3.0.0",
+ "strip-ansi": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/chokidar-cli/node_modules/yargs": {
+ "version": "13.3.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^5.0.0",
+ "find-up": "^3.0.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^3.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^13.1.2"
+ }
+ },
+ "node_modules/chokidar-cli/node_modules/yargs-parser": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ }
+ },
"node_modules/cliui": {
"version": "8.0.1",
"dev": true,
@@ -1483,6 +1618,8 @@
},
"node_modules/copyfiles": {
"version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
+ "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1574,6 +1711,16 @@
"ms": "2.0.0"
}
},
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/define-lazy-prop": {
"version": "2.0.0",
"dev": true,
@@ -1753,6 +1900,22 @@
"node": ">= 0.6"
}
},
+ "node_modules/event-stream": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
+ "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "duplexer": "~0.1.1",
+ "from": "~0",
+ "map-stream": "~0.1.0",
+ "pause-stream": "0.0.11",
+ "split": "0.3",
+ "stream-combiner": "~0.0.4",
+ "through": "~2.3.1"
+ }
+ },
"node_modules/eventemitter3": {
"version": "4.0.7",
"license": "MIT",
@@ -1774,6 +1937,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/finalhandler": {
"version": "1.1.2",
"dev": true,
@@ -1791,6 +1967,19 @@
"node": ">= 0.8"
}
},
+ "node_modules/find-up": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/foreground-child": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
@@ -1919,6 +2108,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/gopd": {
"version": "1.2.0",
"license": "MIT",
@@ -2010,6 +2212,19 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-docker": {
"version": "2.2.1",
"dev": true,
@@ -2051,6 +2266,16 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
"node_modules/isarray": {
"version": "0.0.1",
"dev": true,
@@ -2089,11 +2314,39 @@
"license": "MIT",
"peer": true
},
+ "node_modules/locate-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/lodash": {
"version": "4.17.21",
"dev": true,
"license": "MIT"
},
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -2105,6 +2358,12 @@
"yallist": "^2.1.2"
}
},
+ "node_modules/map-stream": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
+ "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==",
+ "dev": true
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"license": "MIT",
@@ -2208,6 +2467,13 @@
"node": ">= 0.6"
}
},
+ "node_modules/node-cleanup": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz",
+ "integrity": "sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/noms": {
"version": "0.0.0",
"dev": true,
@@ -2298,6 +2564,45 @@
"node": ">=8"
}
},
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -2323,6 +2628,16 @@
"node": ">= 0.8"
}
},
+ "node_modules/path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/path-is-absolute": {
"version": "1.0.1",
"dev": true,
@@ -2394,6 +2709,8 @@
},
"node_modules/picomatch": {
"version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2463,6 +2780,22 @@
"node": ">=0.8.0"
}
},
+ "node_modules/ps-tree": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
+ "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "event-stream": "=3.3.4"
+ },
+ "bin": {
+ "ps-tree": "bin/ps-tree.js"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@@ -2508,6 +2841,19 @@
"string_decoder": "~0.10.x"
}
},
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"dev": true,
@@ -2516,6 +2862,13 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/rimraf": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
@@ -2695,6 +3048,13 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/setprototypeof": {
"version": "1.2.0",
"dev": true,
@@ -2822,6 +3182,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "through": "2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/statuses": {
"version": "1.5.0",
"dev": true,
@@ -2830,11 +3203,31 @@
"node": ">= 0.6"
}
},
+ "node_modules/stream-combiner": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
+ "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "duplexer": "~0.1.1"
+ }
+ },
"node_modules/string_decoder": {
"version": "0.10.31",
"dev": true,
"license": "MIT"
},
+ "node_modules/string-argv": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"dev": true,
@@ -2949,6 +3342,19 @@
"safe-buffer": "~5.1.0"
}
},
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"dev": true,
@@ -2965,6 +3371,28 @@
"tree-kill": "cli.js"
}
},
+ "node_modules/tsc-watch": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/tsc-watch/-/tsc-watch-7.1.1.tgz",
+ "integrity": "sha512-r6t37Dkk4vK44HwxOe+OzjpE/gDamZAwqXhtcAJD/hPVblcjJK45NxbK0HcDASXG0U4pEnCh640JZbeDVSC6yA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "node-cleanup": "^2.1.2",
+ "ps-tree": "^1.2.0",
+ "string-argv": "^0.3.2"
+ },
+ "bin": {
+ "tsc-watch": "dist/lib/tsc-watch.js"
+ },
+ "engines": {
+ "node": ">=12.12.0"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"dev": true,
@@ -3100,6 +3528,13 @@
"node": ">= 8"
}
},
+ "node_modules/which-module": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"dev": true,
@@ -3209,6 +3644,22 @@
"@types/node": "20.14.9"
}
},
+ "spine-construct3": {
+ "name": "@esotericsoftware/spine-construct3",
+ "version": "4.2.82",
+ "license": "LicenseRef-LICENSE",
+ "dependencies": {
+ "@esotericsoftware/spine-construct3-lib": "^4.2.82"
+ }
+ },
+ "spine-construct3-lib": {
+ "name": "@esotericsoftware/spine-construct3-lib",
+ "version": "4.2.82",
+ "license": "LicenseRef-LICENSE",
+ "dependencies": {
+ "@esotericsoftware/spine-core": "4.2.82"
+ }
+ },
"spine-core": {
"name": "@esotericsoftware/spine-core",
"version": "4.2.82",
diff --git a/spine-ts/package.json b/spine-ts/package.json
index 2c6e1d623..8c4c707b4 100644
--- a/spine-ts/package.json
+++ b/spine-ts/package.json
@@ -8,14 +8,17 @@
],
"scripts": {
"prepublish": "npm run clean && npm run build",
- "clean": "npx rimraf spine-core/dist spine-canvas/dist spine-canvaskit/dist spine-webgl/dist spine-phaser-v3/dist spine-phaser-v4/dist spine-player/dist spine-threejs/dist spine-pixi-v7/dist spine-pixi-v8/dist spine-webcomponents/dist",
- "build": "npm run clean && npm run build:modules && concurrently 'npm run build:core:iife' 'npm run build:core:esm' 'npm run build:canvas:iife' 'npm run build:canvas:esm' 'npm run build:canvaskit:iife' 'npm run build:canvaskit:esm' 'npm run build:webgl:iife' 'npm run build:webgl:esm' 'npm run build:phaser-v3:iife' 'npm run build:phaser-v4:iife' 'npm run build:phaser-v3:esm' 'npm run build:phaser-v4:esm' 'npm run build:player:iife' 'npm run build:player:esm' 'npm run build:player:css' 'npm run build:threejs:iife' 'npm run build:threejs:esm' 'npm run build:pixi-v7:iife' 'npm run build:pixi-v7:esm' 'npm run build:pixi-v8:iife' 'npm run build:pixi-v8:esm' 'npm run build:webcomponents:iife' 'npm run build:webcomponents:esm'",
+ "clean": "npx rimraf spine-core/dist spine-canvas/dist spine-canvaskit/dist spine-webgl/dist spine-phaser-v3/dist spine-phaser-v4/dist spine-player/dist spine-threejs/dist spine-pixi-v7/dist spine-pixi-v8/dist spine-webcomponents/dist spine-construct3/dist spine-construct3-lib/dist",
+ "build": "npm run clean && npm run build:modules && concurrently 'npm run build:core:iife' 'npm run build:core:esm' 'npm run build:canvas:iife' 'npm run build:canvas:esm' 'npm run build:canvaskit:iife' 'npm run build:canvaskit:esm' 'npm run build:webgl:iife' 'npm run build:webgl:esm' 'npm run build:phaser-v3:iife' 'npm run build:phaser-v4:iife' 'npm run build:phaser-v3:esm' 'npm run build:phaser-v4:esm' 'npm run build:player:iife' 'npm run build:player:esm' 'npm run build:player:css' 'npm run build:threejs:iife' 'npm run build:threejs:esm' 'npm run build:pixi-v7:iife' 'npm run build:pixi-v7:esm' 'npm run build:pixi-v8:iife' 'npm run build:pixi-v8:esm' 'npm run build:webcomponents:iife' 'npm run build:webcomponents:esm' 'npm run build:construct3' 'npm run build:construct3-lib'",
"format": "npx -y tsx scripts/format.ts",
"lint": "npx biome lint .",
"postbuild": "npm run minify",
"build:modules": "npx tsc -b -clean && npx tsc -b",
"build:core:iife": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/iife/spine-core.js --format=iife --global-name=spine",
"build:core:esm": "npx esbuild --bundle spine-core/src/index.ts --tsconfig=spine-core/tsconfig.json --sourcemap --outfile=spine-core/dist/esm/spine-core.mjs --format=esm --global-name=spine",
+ "build:construct3": "npx tsc --project spine-construct3/tsconfig.json && npm run build:construct3:copy-assets",
+ "build:construct3:copy-assets": "npx copyfiles -u 2 \"spine-construct3/src/**/*.json\" \"spine-construct3/src/**/*.svg\" spine-construct3/dist/ && cp spine-construct3-lib/dist/iife/spine-construct3-lib.js spine-construct3/dist/c3runtime",
+ "build:construct3-lib": "node spine-construct3-lib/esbuild.config.js",
"build:canvas:iife": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/iife/spine-canvas.js --format=iife --global-name=spine",
"build:canvas:esm": "npx esbuild --bundle spine-canvas/src/index.ts --tsconfig=spine-canvas/tsconfig.json --sourcemap --outfile=spine-canvas/dist/esm/spine-canvas.mjs --format=esm --global-name=spine",
"build:canvaskit:iife": "npx esbuild --bundle spine-canvaskit/src/index.ts --tsconfig=spine-canvaskit/tsconfig.json --sourcemap --outfile=spine-canvaskit/dist/iife/spine-canvaskit.js --external:canvaskit-wasm --format=iife --global-name=spine",
@@ -38,10 +41,12 @@
"build:webcomponents:iife": "npx esbuild --bundle spine-webcomponents/src/index.ts --tsconfig=spine-webcomponents/tsconfig.json --sourcemap --outfile=spine-webcomponents/dist/iife/spine-webcomponents.js --format=iife --global-name=spine",
"build:webcomponents:esm": "npx esbuild --bundle spine-webcomponents/src/index.ts --tsconfig=spine-webcomponents/tsconfig.json --sourcemap --outfile=spine-webcomponents/dist/esm/spine-webcomponents.mjs --format=esm --global-name=spine",
"minify": "npx esbuild --minify spine-core/dist/iife/spine-core.js --outfile=spine-core/dist/iife/spine-core.min.js && npx esbuild --minify spine-core/dist/esm/spine-core.mjs --outfile=spine-core/dist/esm/spine-core.min.mjs && npx esbuild --minify spine-canvas/dist/iife/spine-canvas.js --outfile=spine-canvas/dist/iife/spine-canvas.min.js && npx esbuild --minify spine-canvas/dist/esm/spine-canvas.mjs --outfile=spine-canvas/dist/esm/spine-canvas.min.mjs && npx esbuild --minify spine-canvaskit/dist/iife/spine-canvaskit.js --outfile=spine-canvaskit/dist/iife/spine-canvaskit.min.js && npx esbuild --minify spine-canvaskit/dist/esm/spine-canvaskit.mjs --outfile=spine-canvaskit/dist/esm/spine-canvaskit.min.mjs && npx esbuild --minify spine-player/dist/iife/spine-player.js --outfile=spine-player/dist/iife/spine-player.min.js && npx esbuild --minify spine-player/dist/esm/spine-player.mjs --outfile=spine-player/dist/esm/spine-player.min.mjs && npx esbuild --minify spine-phaser-v3/dist/iife/spine-phaser-v3.js --outfile=spine-phaser-v3/dist/iife/spine-phaser-v3.min.js && npx esbuild --minify spine-phaser-v3/dist/esm/spine-phaser-v3.mjs --outfile=spine-phaser-v3/dist/esm/spine-phaser-v3.min.mjs && npx esbuild --minify spine-phaser-v4/dist/iife/spine-phaser-v4.js --outfile=spine-phaser-v4/dist/iife/spine-phaser-v4.min.js && npx esbuild --minify spine-phaser-v4/dist/esm/spine-phaser-v4.mjs --outfile=spine-phaser-v4/dist/esm/spine-phaser-v4.min.mjs && npx esbuild --minify spine-webgl/dist/iife/spine-webgl.js --outfile=spine-webgl/dist/iife/spine-webgl.min.js && npx esbuild --minify spine-webgl/dist/esm/spine-webgl.mjs --outfile=spine-webgl/dist/esm/spine-webgl.min.mjs && npx esbuild --minify spine-threejs/dist/iife/spine-threejs.js --outfile=spine-threejs/dist/iife/spine-threejs.min.js && npx esbuild --minify spine-threejs/dist/esm/spine-threejs.mjs --outfile=spine-threejs/dist/esm/spine-threejs.min.mjs && npx esbuild --minify spine-pixi-v7/dist/iife/spine-pixi-v7.js --outfile=spine-pixi-v7/dist/iife/spine-pixi-v7.min.js && npx esbuild --minify spine-pixi-v7/dist/esm/spine-pixi-v7.mjs --outfile=spine-pixi-v7/dist/esm/spine-pixi-v7.min.mjs && npx esbuild --minify spine-pixi-v8/dist/iife/spine-pixi-v8.js --outfile=spine-pixi-v8/dist/iife/spine-pixi-v8.min.js && npx esbuild --minify spine-pixi-v8/dist/esm/spine-pixi-v8.mjs --outfile=spine-pixi-v8/dist/esm/spine-pixi-v8.min.mjs && npx esbuild --minify spine-webcomponents/dist/iife/spine-webcomponents.js --outfile=spine-webcomponents/dist/iife/spine-webcomponents.min.js && npx esbuild --minify spine-webcomponents/dist/esm/spine-webcomponents.mjs --outfile=spine-webcomponents/dist/esm/spine-webcomponents.min.mjs",
- "dev": "concurrently \"npx alive-server\" \"npm run dev:canvas\" \"npm run dev:canvaskit\" \"npm run dev:webgl\" \"npm run dev:phaser-v3\" \"npm run dev:phaser-v4\" \"npm run dev:player\" \"npm run dev:threejs\" \"npm run dev:pixi-v7\" \"npm run dev:pixi-v8\" \"npm run dev:webcomponents\" \"npm run dev:modules\"",
+ "dev": "concurrently \"npx alive-server --cors\" \"npm run dev:canvas\" \"npm run dev:canvaskit\" \"npm run dev:webgl\" \"npm run dev:phaser-v3\" \"npm run dev:phaser-v4\" \"npm run dev:player\" \"npm run dev:threejs\" \"npm run dev:pixi-v7\" \"npm run dev:pixi-v8\" \"npm run dev:webcomponents\" \"npm run dev:modules\" \"npm run dev:construct3\" \"npm run dev:construct3-lib\"",
"dev:modules": "npm run build:modules -- --watch",
"dev:canvas": "concurrently \"npm run build:canvas:iife -- --watch\" \"npm run build:canvas:esm -- --watch\"",
"dev:canvaskit": "concurrently \"npm run build:canvaskit:iife -- --watch\" \"npm run build:canvaskit:esm -- --watch\"",
+ "dev:construct3": "tsc-watch --project spine-construct3/tsconfig.json --onCompilationComplete \"npm run build:construct3:copy-assets\"",
+ "dev:construct3-lib": "npm run build:construct3-lib -- --watch",
"dev:webgl": "concurrently \"npm run build:webgl:iife -- --watch\" \"npm run build:webgl:esm -- --watch\"",
"dev:phaser-v3": "concurrently \"npm run build:phaser-v3:iife -- --watch\" \"npm run build:phaser-v3:esm -- --watch\"",
"dev:phaser-v4": "concurrently \"npm run build:phaser-v4:iife -- --watch\" \"npm run build:phaser-v4:esm -- --watch\"",
@@ -73,13 +78,15 @@
"workspaces": [
"spine-core",
"spine-canvas",
+ "spine-canvaskit",
+ "spine-construct3",
+ "spine-construct3-lib",
"spine-phaser-v3",
"spine-phaser-v4",
"spine-player",
"spine-threejs",
"spine-pixi-v7",
"spine-pixi-v8",
- "spine-canvaskit",
"spine-webgl",
"spine-webcomponents"
],
@@ -87,10 +94,12 @@
"@biomejs/biome": "^2.1.1",
"@types/offscreencanvas": "^2019.7.3",
"alive-server": "^1.3.0",
+ "chokidar-cli": "^3.0.0",
"concurrently": "^9.2.0",
"copyfiles": "^2.4.1",
"esbuild": "^0.25.6",
"rimraf": "^6.0.1",
+ "tsc-watch": "^7.1.1",
"typescript": "^5.8.3",
"typescript-formatter": "^7.2.2"
}
diff --git a/spine-ts/spine-construct3-lib/LICENSE b/spine-ts/spine-construct3-lib/LICENSE
new file mode 100644
index 000000000..d03d3caed
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/LICENSE
@@ -0,0 +1,26 @@
+Spine Runtimes License Agreement
+Last updated April 5, 2025. Replaces all prior versions.
+
+Copyright (c) 2013-2025, Esoteric Software LLC
+
+Integration of the Spine Runtimes into software or otherwise creating
+derivative works of the Spine Runtimes is permitted under the terms and
+conditions of Section 2 of the Spine Editor License Agreement:
+http://esotericsoftware.com/spine-editor-license
+
+Otherwise, it is permitted to integrate the Spine Runtimes into software
+or otherwise create derivative works of the Spine Runtimes (collectively,
+"Products"), provided that each user of the Products must obtain their own
+Spine Editor license and redistribution of the Products in any form must
+include this license and copyright notice.
+
+THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/spine-ts/spine-construct3-lib/README.md b/spine-ts/spine-construct3-lib/README.md
new file mode 100644
index 000000000..577c4f38a
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/README.md
@@ -0,0 +1,3 @@
+# spine-ts THREE.JS
+
+Please see the top-level [README.md](../README.md) for more information.
\ No newline at end of file
diff --git a/spine-ts/spine-construct3-lib/esbuild.config.js b/spine-ts/spine-construct3-lib/esbuild.config.js
new file mode 100644
index 000000000..e9d2b444b
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/esbuild.config.js
@@ -0,0 +1,52 @@
+// build.js
+import * as fs from 'node:fs';
+import * as esbuild from 'esbuild';
+
+// Plugin to append string after build
+const appendStringPlugin = {
+ name: 'append-string',
+ setup(build) {
+ build.onEnd((result) => {
+ if (result.errors.length === 0) {
+ const outputFile = 'spine-construct3-lib/dist/iife/spine-construct3-lib.js';
+
+ try {
+ const content = fs.readFileSync(outputFile, 'utf8');
+ const appendString = 'if(!globalThis.spine)globalThis.spine=spine';
+
+ // Only append if not already present
+ if (!content.includes(appendString)) {
+ fs.writeFileSync(outputFile, `${content}\n${appendString}`);
+ console.log('✓ Appended spine global assignment');
+ }
+ } catch (err) {
+ console.error('Error appending string:', err);
+ }
+ }
+ });
+ }
+};
+
+// Check if watch mode is requested
+const isWatch = process.argv.includes('--watch');
+
+// Build configuration
+const buildOptions = {
+ entryPoints: ['spine-construct3-lib/src/index.ts'],
+ bundle: true,
+ outfile: 'spine-construct3-lib/dist/iife/spine-construct3-lib.js',
+ tsconfig: 'spine-construct3-lib/tsconfig.json',
+ sourcemap: true,
+ format: 'iife',
+ globalName: 'spine',
+ plugins: [appendStringPlugin],
+};
+
+if (isWatch) {
+ const ctx = await esbuild.context(buildOptions);
+ await ctx.watch();
+ console.log('👀 Watching for changes...');
+} else {
+ await esbuild.build(buildOptions);
+ console.log('✅ Build complete');
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3-lib/package.json b/spine-ts/spine-construct3-lib/package.json
new file mode 100644
index 000000000..3ca49d1b3
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "@esotericsoftware/spine-construct3-lib",
+ "version": "4.2.82",
+ "description": "The official Spine Runtimes for the web.",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "type": "module",
+ "files": [
+ "dist/**/*",
+ "README.md",
+ "LICENSE"
+ ],
+ "scripts": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
+ },
+ "keywords": [
+ "gamedev",
+ "animations",
+ "2d",
+ "spine",
+ "game-dev",
+ "runtimes",
+ "skeletal"
+ ],
+ "author": "Esoteric Software LLC",
+ "license": "LicenseRef-LICENSE",
+ "bugs": {
+ "url": "https://github.com/esotericsoftware/spine-runtimes/issues"
+ },
+ "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
+ "dependencies": {
+ "@esotericsoftware/spine-core": "4.2.82"
+ }
+}
diff --git a/spine-ts/spine-construct3-lib/src/AssetLoader.ts b/spine-ts/spine-construct3-lib/src/AssetLoader.ts
new file mode 100644
index 000000000..dc81cdf31
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/src/AssetLoader.ts
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated April 5, 2025. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2025, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+import { AtlasAttachmentLoader, SkeletonBinary, SkeletonJson, TextureAtlas } from "@esotericsoftware/spine-core";
+import { C3Texture, C3TextureEditor } from "./C3Texture";
+
+
+export class AssetLoader {
+ constructor (private type: "editor" | "runtime") {
+ }
+
+ public async loadSkeletonEditor (path: string, textureAtlas: TextureAtlas, instance: SDK.IWorldInstance) {
+ const projectFile = instance.GetProject().GetProjectFileByName(path);
+ if (!projectFile) return null;
+
+ const blob = projectFile.GetBlob();
+ const atlasLoader = new AtlasAttachmentLoader(textureAtlas);
+
+ const isBinary = path.endsWith(".skel");
+ if (isBinary) {
+ const skeletonFile = await blob.arrayBuffer();
+ const skeletonLoader = new SkeletonBinary(atlasLoader);
+ skeletonLoader.scale = 1;
+ return skeletonLoader.readSkeletonData(skeletonFile);
+ }
+
+ const skeletonFile = await blob.text();
+ const skeletonLoader = new SkeletonJson(atlasLoader);
+ skeletonLoader.scale = 1;
+ return skeletonLoader.readSkeletonData(skeletonFile);
+ }
+
+ public async loadAtlasEditor (path: string, instance: SDK.IWorldInstance, renderer: SDK.Gfx.IWebGLRenderer) {
+ const projectFile = instance.GetProject().GetProjectFileByName(path);
+ if (!projectFile) return null;
+
+ const blob = projectFile.GetBlob();
+ const content = await blob.text();
+
+ const textureAtlas = new TextureAtlas(content);
+ await Promise.all(textureAtlas.pages.map(async page => {
+ const texture = await this.loadSpineTextureEditor(page.name, page.pma, instance);
+ if (texture) {
+ const spineTexture = new C3TextureEditor(texture, renderer);
+ page.setTexture(spineTexture);
+ }
+ return texture;
+ }));
+
+ return textureAtlas;
+ }
+
+ public async loadSpineTextureEditor (pageName: string, pma = false, instance: SDK.IWorldInstance) {
+ const projectFile = instance.GetProject().GetProjectFileByName(pageName);
+ if (!projectFile) {
+ throw new Error(`An error occured while loading the texture: ${pageName}`);
+ }
+
+ const content = projectFile.GetBlob();
+ return this.createImageBitmapFromBlob(content, pma);
+ }
+
+ public async loadSkeletonRuntime (path: string, textureAtlas: TextureAtlas, scale = 1, instance: IRuntime) {
+ const fullPath = await instance.assets.getProjectFileUrl(path);
+ if (!fullPath) return null;
+
+ const content = await instance.assets.fetchArrayBuffer(fullPath);
+ if (!content) return null;
+
+ const atlasLoader = new AtlasAttachmentLoader(textureAtlas);
+
+ const isBinary = path.endsWith(".skel");
+ if (isBinary) {
+ const skeletonLoader = new SkeletonBinary(atlasLoader);
+ skeletonLoader.scale = scale;
+ return skeletonLoader.readSkeletonData(content);
+ }
+
+ const skeletonLoader = new SkeletonJson(atlasLoader);
+ skeletonLoader.scale = scale;
+ return skeletonLoader.readSkeletonData(content);
+ }
+
+ public async loadAtlasRuntime (path: string, instance: IRuntime, renderer: IRenderer) {
+ const fullPath = await instance.assets.getProjectFileUrl(path);
+ if (!fullPath) return null;
+
+ const content = await instance.assets.fetchText(fullPath);
+ if (!content) return null;
+
+ const textureAtlas = new TextureAtlas(content);
+ await Promise.all(textureAtlas.pages.map(async page => {
+ const texture = await this.loadSpineTextureRuntime(page.name, page.pma, instance);
+ if (texture) {
+ const spineTexture = new C3Texture(texture, renderer);
+ page.setTexture(spineTexture);
+ }
+ return texture;
+ }));
+ return textureAtlas;
+ }
+
+ public async loadSpineTextureRuntime (pageName: string, pma = false, instance: IRuntime) {
+ const fullPath = await instance.assets.getProjectFileUrl(pageName);
+ if (!fullPath) return null;
+
+ const content = await instance.assets.fetchBlob(fullPath);
+ if (!content) return null;
+
+ return this.createImageBitmapFromBlob(content, pma);
+ }
+
+ private async createImageBitmapFromBlob (blob: Blob, pma: boolean): Promise {
+ try {
+ return createImageBitmap(blob, { premultiplyAlpha: pma ? "none" : "premultiply" });
+ } catch (e) {
+ console.error("Failed to create ImageBitmap from blob:", e);
+ return null;
+ }
+ }
+
+}
+
+
diff --git a/spine-ts/spine-construct3-lib/src/C3Texture.ts b/spine-ts/spine-construct3-lib/src/C3Texture.ts
new file mode 100644
index 000000000..878d8cc4f
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/src/C3Texture.ts
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated April 5, 2025. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2025, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+import { BlendMode, Texture, type TextureFilter, type TextureWrap } from "@esotericsoftware/spine-core";
+
+export class C3TextureEditor extends Texture {
+ texture: SDK.Gfx.IWebGLTexture;
+ renderer: SDK.Gfx.IWebGLRenderer;
+
+ constructor (image: HTMLImageElement | ImageBitmap, renderer: SDK.Gfx.IWebGLRenderer) {
+ super(image);
+ this.renderer = renderer;
+ this.texture = renderer.CreateDynamicTexture(image.width, image.height);
+ this.renderer.UpdateTexture(image, this.texture);
+ }
+
+ setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
+ }
+
+ setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
+ }
+
+ dispose () {
+ this.renderer.DeleteTexture(this.texture);
+ }
+}
+
+export class C3Texture extends Texture {
+ texture: ITexture;
+ renderer: IRenderer;
+
+ constructor (image: HTMLImageElement | ImageBitmap, renderer: IRenderer) {
+ super(image);
+ this.renderer = renderer;
+ this.texture = renderer.createDynamicTexture(image.width, image.height);
+ this.renderer.updateTexture(image, this.texture);
+ }
+
+ setFilters (minFilter: TextureFilter, magFilter: TextureFilter) {
+ }
+
+ setWraps (uWrap: TextureWrap, vWrap: TextureWrap) {
+ }
+
+ dispose () {
+ this.renderer.deleteTexture(this.texture);
+ }
+}
+
+export const BlendingModeSpineToC3: Record = {
+ [BlendMode.Normal]: "normal",
+ [BlendMode.Additive]: "additive",
+ [BlendMode.Multiply]: "normal",
+ [BlendMode.Screen]: "normal",
+}
+
diff --git a/spine-ts/spine-construct3-lib/src/SpineBoundsProvider.ts b/spine-ts/spine-construct3-lib/src/SpineBoundsProvider.ts
new file mode 100644
index 000000000..7c67a9f30
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/src/SpineBoundsProvider.ts
@@ -0,0 +1,133 @@
+import { AnimationState, Physics, Skeleton, SkeletonClipping, Skin } from "@esotericsoftware/spine-core";
+
+interface Rectangle {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+}
+
+interface GameObject {
+ skeleton?: Skeleton,
+ state?: AnimationState,
+}
+
+export interface SpineBoundsProvider {
+ /** Returns the bounding box for the skeleton, in skeleton space. */
+ calculateBounds (gameObject: GameObject): Rectangle;
+}
+
+export class AABBRectangleBoundsProvider implements SpineBoundsProvider {
+ constructor (
+ private x: number,
+ private y: number,
+ private width: number,
+ private height: number,
+ ) { }
+ calculateBounds () {
+ return { x: this.x, y: this.y, width: this.width, height: this.height };
+ }
+}
+
+export class SetupPoseBoundsProvider implements SpineBoundsProvider {
+ /**
+ * @param clipping If true, clipping attachments are used to compute the bounds. False, by default.
+ */
+ constructor (private clipping = false) { }
+
+ calculateBounds (gameObject: GameObject) {
+ if (!gameObject.skeleton) return { x: 0, y: 0, width: 0, height: 0 };
+ // Make a copy of animation state and skeleton as this might be called while
+ // the skeleton in the GameObject has already been heavily modified. We can not
+ // reconstruct that state.
+ const skeleton = new Skeleton(gameObject.skeleton.data);
+ skeleton.setupPose();
+ skeleton.updateWorldTransform(Physics.update);
+ const bounds = skeleton.getBoundsRect(this.clipping ? new SkeletonClipping() : undefined);
+ return bounds.width === Number.NEGATIVE_INFINITY
+ ? { x: 0, y: 0, width: 0, height: 0 }
+ : bounds;
+ }
+}
+
+export class SkinsAndAnimationBoundsProvider implements SpineBoundsProvider {
+ /**
+ * @param animation The animation to use for calculating the bounds. If null, the setup pose is used.
+ * @param skins The skins to use for calculating the bounds. If empty, the default skin is used.
+ * @param timeStep The time step to use for calculating the bounds. A smaller time step means more precision, but slower calculation.
+ * @param clipping If true, clipping attachments are used to compute the bounds. False, by default.
+ */
+ constructor (
+ private animation?: string,
+ private skins: string[] = [],
+ private timeStep: number = 0.05,
+ private clipping = false,
+ ) { }
+
+ calculateBounds (gameObject: GameObject): {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+ } {
+ if (!gameObject.skeleton || !gameObject.state)
+ return { x: 0, y: 0, width: 0, height: 0 };
+ // Make a copy of animation state and skeleton as this might be called while
+ // the skeleton in the GameObject has already been heavily modified. We can not
+ // reconstruct that state.
+ const animationState = new AnimationState(gameObject.state.data);
+ const skeleton = new Skeleton(gameObject.skeleton.data);
+ const clipper = this.clipping ? new SkeletonClipping() : undefined;
+ const data = skeleton.data;
+ if (this.skins.length > 0) {
+ const customSkin = new Skin("custom-skin");
+ for (const skinName of this.skins) {
+ const skin = data.findSkin(skinName);
+ if (skin == null) continue;
+ customSkin.addSkin(skin);
+ }
+ skeleton.setSkin(customSkin);
+ }
+ skeleton.setupPose();
+
+ const animation = this.animation != null ? data.findAnimation(this.animation!) : null;
+
+ if (animation == null) {
+ skeleton.updateWorldTransform(Physics.update);
+ const bounds = skeleton.getBoundsRect(clipper);
+ return bounds.width === Number.NEGATIVE_INFINITY
+ ? { x: 0, y: 0, width: 0, height: 0 }
+ : bounds;
+ } else {
+ let minX = Number.POSITIVE_INFINITY,
+ minY = Number.POSITIVE_INFINITY,
+ maxX = Number.NEGATIVE_INFINITY,
+ maxY = Number.NEGATIVE_INFINITY;
+ animationState.clearTracks();
+ animationState.setAnimation(0, animation, false);
+ const steps = Math.max(animation.duration / this.timeStep, 1.0);
+ for (let i = 0; i < steps; i++) {
+ const delta = i > 0 ? this.timeStep : 0;
+ animationState.update(delta);
+ animationState.apply(skeleton);
+ skeleton.update(delta);
+ skeleton.updateWorldTransform(Physics.update);
+
+ const bounds = skeleton.getBoundsRect(clipper);
+ minX = Math.min(minX, bounds.x);
+ minY = Math.min(minY, bounds.y);
+ maxX = Math.max(maxX, bounds.x + bounds.width);
+ maxY = Math.max(maxY, bounds.y + bounds.height);
+ }
+ const bounds = {
+ x: minX,
+ y: minY,
+ width: maxX - minX,
+ height: maxY - minY,
+ };
+ return bounds.width === Number.NEGATIVE_INFINITY
+ ? { x: 0, y: 0, width: 0, height: 0 }
+ : bounds;
+ }
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3-lib/src/index.ts b/spine-ts/spine-construct3-lib/src/index.ts
new file mode 100644
index 000000000..a351846fc
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/src/index.ts
@@ -0,0 +1,4 @@
+export * from "@esotericsoftware/spine-core";
+export * from './AssetLoader.js';
+export * from './C3Texture.js';
+export * from './SpineBoundsProvider.js';
diff --git a/spine-ts/spine-construct3-lib/tsconfig.json b/spine-ts/spine-construct3-lib/tsconfig.json
new file mode 100644
index 000000000..701215705
--- /dev/null
+++ b/spine-ts/spine-construct3-lib/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "extends": "../tsconfig.base.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "rootDir": "./src",
+ "outDir": "./dist",
+ "paths": {
+ "@esotericsoftware/spine-core": ["../spine-core/src"]
+ }
+ },
+ "include": ["**/*.ts", "../spine-construct3/ts-defs/**/*.d.ts"],
+ "exclude": ["dist/**/*.d.ts", "example/**/*.ts"],
+ "references": [
+ {
+ "path": "../spine-core"
+ }
+ ]
+}
diff --git a/spine-ts/spine-construct3/aces.schema.json b/spine-ts/spine-construct3/aces.schema.json
new file mode 100644
index 000000000..6d5bc77f4
--- /dev/null
+++ b/spine-ts/spine-construct3/aces.schema.json
@@ -0,0 +1,249 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://construct.net/sdk/schema/plugin.addon.schema.json",
+ "title": "Plugin aces.json",
+ "description": "Plugin JSON file that describes the available actions, conditions and expressions.",
+ "type": "object",
+ "properties": {
+ "$schema": { "type": "string" }
+ },
+ "additionalProperties": {
+ "description": "ACE definitions for a specific category.",
+ "type": "object",
+ "properties": {
+ "conditions": {
+ "description": "Condition definitions for this category.",
+ "type": "array",
+ "items": {
+ "description": "Condition definition",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A string specifying a unique ID for the condition.",
+ "type": "string"
+ },
+ "c2id": {
+ "description": "If you are porting a Construct 2 addon to Construct 3, put the corresponding numerical ID that the Construct 2 addon used here. This allows Construct 3 to import Construct 2 projects using your addon.",
+ "type": "number"
+ },
+ "scriptName": {
+ "description": "The name of the function in the runtime script for this condition.",
+ "type": "string"
+ },
+ "isDeprecated": {
+ "description": "Set to true to deprecate the condition. This hides it in the editor, but allows existing projects to continue using it.",
+ "type": "boolean"
+ },
+ "highlight": {
+ "description": "Set to true to highlight the condition in the picker dialog.",
+ "type": "boolean"
+ },
+ "isTrigger": {
+ "description": "Specifies a trigger condition. This appears with an arrow in the event sheet. Instead of being evaluated every tick, triggers only run when they are explicity triggered by a runtime call.",
+ "type": "boolean"
+ },
+ "isFakeTrigger": {
+ "description": "Specifies a fake trigger. This appears identical to a trigger in the event sheet, but is actually evaluated every tick. This is useful for conditions which are true for a single tick, such as for APIs which must poll a value every tick.",
+ "type": "boolean"
+ },
+ "isStatic": {
+ "description": "Normally, the condition runtime method is executed once per picked instance. If the condition is marked static, the runtime method is executed once only, on the object type class. This means the runtime method must also implement the instance picking entirely itself, including respecting negation and OR blocks.",
+ "type": "boolean"
+ },
+ "isLooping": {
+ "description": "Display an icon in the event sheet to indicate the condition loops. This should only be used with conditions which implement re-triggering.",
+ "type": "boolean"
+ },
+ "isInvertible": {
+ "description": "Allow the condition to be inverted in the event sheet. Set to false to disable invert.",
+ "type": "boolean"
+ },
+ "isCompatibleWithTriggers": {
+ "description": "Allow the condition to be used in the same branch as a trigger. Set to false if the condition does not make sense when used in a trigger, such as the Trigger once condition.",
+ "type": "boolean"
+ },
+ "params": {
+ "description": "Array of parameters for this condition.",
+ "type": "array",
+ "items": { "$ref": "#/$defs/acParameter" }
+ }
+ },
+ "required": ["id", "scriptName"],
+ "additionalProperties": false
+ }
+ },
+ "actions": {
+ "description": "Action definitions for this category.",
+ "type": "array",
+ "items": {
+ "description": "Action definition",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A string specifying a unique ID for the action.",
+ "type": "string"
+ },
+ "c2id": {
+ "description": "If you are porting a Construct 2 addon to Construct 3, put the corresponding numerical ID that the Construct 2 addon used here. This allows Construct 3 to import Construct 2 projects using your addon.",
+ "type": "number"
+ },
+ "scriptName": {
+ "description": "The name of the function in the runtime script for this action.",
+ "type": "string"
+ },
+ "isDeprecated": {
+ "description": "Set to true to deprecate the action. This hides it in the editor, but allows existing projects to continue using it.",
+ "type": "boolean"
+ },
+ "highlight": {
+ "description": "Set to true to highlight the action in the picker dialog.",
+ "type": "boolean"
+ },
+ "isAsync": {
+ "description": "Set to true to mark the action as asynchronous. Make the action method an async function, and the system 'Wait for previous actions to complete' action will be able to wait for the action as well.",
+ "type": "boolean"
+ },
+ "params": {
+ "description": "Array of parameters for this action.",
+ "type": "array",
+ "items": { "$ref": "#/$defs/acParameter" }
+ }
+ },
+ "required": ["id", "scriptName"],
+ "additionalProperties": false
+ }
+ },
+ "expressions": {
+ "description": "Expression definitions for this category.",
+ "type": "array",
+ "items": {
+ "description": "Expression definition",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A string specifying a unique ID for the expression.",
+ "type": "string"
+ },
+ "c2id": {
+ "description": "If you are porting a Construct 2 addon to Construct 3, put the corresponding numerical ID that the Construct 2 addon used here. This allows Construct 3 to import Construct 2 projects using your addon.",
+ "type": "number"
+ },
+ "expressionName": {
+ "description": "The name typed in by the user for this expression, which is also used as the name of the function in the runtime script.",
+ "type": "string"
+ },
+ "isDeprecated": {
+ "description": "Set to true to deprecate the expression. This hides it in the editor, but allows existing projects to continue using it.",
+ "type": "boolean"
+ },
+ "highlight": {
+ "description": "Set to true to highlight the expression in the picker dialog.",
+ "type": "boolean"
+ },
+ "returnType": {
+ "description": "The type of value returned by the expression.",
+ "enum": ["number", "string", "any"]
+ },
+ "isVariadicParameters": {
+ "description": "If true, Construct will allow the user to enter any number of parameters beyond those defined. In other words the parameters (if any) listed in \"params\" are required, but this flag enables adding further \"any\" type parameters beyond the end.",
+ "type": "boolean"
+ },
+ "params": {
+ "description": "Array of parameters for this action.",
+ "type": "array",
+ "items": { "$ref": "#/$defs/expParameter" }
+ }
+ },
+ "required": ["id", "expressionName"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "$defs": {
+ "acParameter": {
+ "description": "A parameter for a condition or action.",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A string with a unique identifier for this parameter.",
+ "type": "string"
+ },
+ "c2id": {
+ "description": "In some circumstances, it is necessary to specify which Construct 2 parameter ID a parameter corresponds to. However normally it can be inferred by the parameter index.",
+ "type": "number"
+ },
+ "type": {
+ "description": "The parameter type.",
+ "enum": ["number", "string", "any", "boolean", "combo", "combo-grouped", "cmp", "object", "objectname", "layer", "layout", "keyb", "instancevar", "instancevarbool", "eventvar", "eventvarbool", "animation", "objinstancevar", "projectfile"]
+ },
+ "initialValue": {
+ "description": "A string which is used as the initial expression for expression-based parameters. Note this is still a string for \"number\" type parameters. It can contain any valid expression for the parameter, such as \"1 + 1\". For \"boolean\" parameters, use a string of either \"true\" or \"false\". For \"combo\" parameters, this is the initial item ID.",
+ "type": "string"
+ },
+ "items": {
+ "description": "Only valid with the \"combo\" type. Set to an array of item IDs available in the dropdown list.",
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1
+ },
+ "itemGroups": {
+ "description": "Only valid with the \"combo-grouped\" type. Set to an array of item groups available in the dropdown list.",
+ "type": "array",
+ "items": {
+ "description": "A combo item group.",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "The combo item group ID.",
+ "type": "string"
+ },
+ "items": {
+ "description": "Array of item IDs available in this item group.",
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1
+ }
+ }
+ },
+ "minItems": 1
+ },
+ "filter": {
+ "description": "Only valid with the \"projectfile\" type. Set to a string of a file extension e.g. \".txt\" to filter the project file list by.",
+ "type": "string"
+ },
+ "allowedPluginIds": {
+ "description": "Optional and only valid with the \"object\" type. Set to an array of plugin IDs allowed to be shown by the object picker. For example, use [\"Sprite\"] to only allow the object parameter to select a Sprite.",
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1
+ },
+ "autocompleteId": {
+ "description": "Optional and only valid with the \"string\" type. Set to a globally unique ID and string constants with the same ID will offer autocomplete in the editor. Useful for tag parameters.",
+ "type": "string"
+ }
+ },
+ "required": ["id", "type"]
+ },
+ "expParameter": {
+ "description": "A parameter for an expression.",
+ "type": "object",
+ "properties": {
+ "id": {
+ "description": "A string with a unique identifier for this parameter.",
+ "type": "string"
+ },
+ "c2id": {
+ "description": "In some circumstances, it is necessary to specify which Construct 2 parameter ID a parameter corresponds to. However normally it can be inferred by the parameter index.",
+ "type": "number"
+ },
+ "type": {
+ "description": "The parameter type.",
+ "enum": ["number", "string", "any"]
+ }
+ },
+ "required": ["id", "type"]
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/package.json b/spine-ts/spine-construct3/package.json
new file mode 100644
index 000000000..988bb5ca2
--- /dev/null
+++ b/spine-ts/spine-construct3/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "@esotericsoftware/spine-construct3",
+ "version": "4.2.82",
+ "description": "The official Spine Runtimes for Construct3",
+ "main": "dist/plugin.js",
+ "types": "dist/plugin.d.ts",
+ "type": "module",
+ "files": [
+ "dist/**/*",
+ "README.md",
+ "LICENSE"
+ ],
+ "scripts": {},
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/esotericsoftware/spine-runtimes.git"
+ },
+ "keywords": [
+ "gamedev",
+ "animations",
+ "2d",
+ "spine",
+ "game-dev",
+ "runtimes",
+ "skeletal"
+ ],
+ "author": "Esoteric Software LLC",
+ "license": "LicenseRef-LICENSE",
+ "bugs": {
+ "url": "https://github.com/esotericsoftware/spine-runtimes/issues"
+ },
+ "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme",
+ "dependencies": {
+ "@esotericsoftware/spine-construct3-lib": "^4.2.82"
+ }
+}
diff --git a/spine-ts/spine-construct3/plugin.addon.schema.json b/spine-ts/spine-construct3/plugin.addon.schema.json
new file mode 100644
index 000000000..bdb338a3a
--- /dev/null
+++ b/spine-ts/spine-construct3/plugin.addon.schema.json
@@ -0,0 +1,73 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://construct.net/sdk/schema/plugin.addon.schema.json",
+ "title": "Plugin addon.json",
+ "description": "Main JSON file that describes metadata about a plugin.",
+ "type": "object",
+ "properties": {
+ "is-c3-addon": {
+ "description": "This is used by Construct to identify valid addons.",
+ "const": true
+ },
+ "sdk-version": {
+ "description": "The version of the Addon SDK used for this addon.",
+ "enum": [1, 2]
+ },
+ "type": {
+ "description": "Indicates the addon type. For the plugin schema, this must be \"plugin\".",
+ "const": "plugin"
+ },
+ "name": {
+ "description": "The displayed name of the addon, in English. This can be changed after release.",
+ "type": "string"
+ },
+ "id": {
+ "description": "The unique ID of the addon. This must not be used by any other addon ever published for Construct, and must never change after you first publish your addon. It is recommended to use a vendor-specific prefix, e.g. MyCompany_MyAddon.",
+ "type": "string"
+ },
+ "version": {
+ "description": "A string specifying the addon version in four parts (major, minor, patch, revision).",
+ "type": "string"
+ },
+ "min-construct-version": {
+ "description": "The minimum Construct version required to use this addon, e.g. \"r400\"",
+ "type": "string"
+ },
+ "supports-worker-mode": {
+ "description": "Whether the addon supports running in worker mode, where the Construct runtime is hosted in a Web Worker. Defaults to true; if set to false the presence of the addon in a project will block the runtime from using worker mode.",
+ "type": "boolean"
+ },
+ "author": {
+ "description": "A string identifying the author of the addon.",
+ "type": "string"
+ },
+ "website": {
+ "description": "A string of a URL to the author's website. It is recommended to provide updates to the addon at this URL if any become available. The website should use HTTPS.",
+ "type": "string",
+ "format": "uri"
+ },
+ "documentation": {
+ "description": "A string of a URL to the online documentation for the addon. It is important to provide documentation for your addon to be useful to users.",
+ "type": "string",
+ "format": "uri"
+ },
+ "description": {
+ "description": "A string of a brief description of what the addon does, displayed when prompting the user to install the addon.",
+ "type": "string"
+ },
+ "editor-scripts": {
+ "description": "An array of script files in the addon package to load in the editor.",
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "file-list": {
+ "description": "A list of all files used by the addon. Required for Developer Mode addons to work.",
+ "type": "array",
+ "items": { "type": "string" }
+ }
+ },
+ "required": ["is-c3-addon", "type", "name", "id", "version", "author", "website", "documentation", "description", "editor-scripts"]
+}
+
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/plugin.lang.schema.json b/spine-ts/spine-construct3/plugin.lang.schema.json
new file mode 100644
index 000000000..8ed024d80
--- /dev/null
+++ b/spine-ts/spine-construct3/plugin.lang.schema.json
@@ -0,0 +1,208 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://construct.net/sdk/schema/plugin.lang.schema.json",
+ "title": "Plugin language file JSON",
+ "description": "The language file with strings for a plugin.",
+ "type": "object",
+ "properties": {
+ "languageTag": {
+ "description": "An IETF language tag defining the translation language, e.g. \"en-US\".",
+ "type": "string"
+ },
+ "fileDescription": {
+ "description": "Optional description for this file (as a comment only).",
+ "type": "string"
+ },
+ "text": {
+ "type": "object",
+ "properties": {
+ "plugins": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "The display name of the plugin.",
+ "type": "string"
+ },
+ "description": {
+ "description": "The description of the plugin.",
+ "type": "string"
+ },
+ "help-url": {
+ "description": "A URL for documentation or support.",
+ "type": "string",
+ "format": "uri"
+ },
+ "properties": {
+ "description": "Language strings for plugin properties.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "Language strings for a plugin property by its ID.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Name of this plugin property.",
+ "type": "string"
+ },
+ "desc": {
+ "description": "Description of this plugin property.",
+ "type": "string"
+ },
+ "items": {
+ "$ref": "#/$defs/comboItems"
+ },
+ "itemGroups": {
+ "$ref": "#/$defs/comboItemGroups"
+ },
+ "link-text": {
+ "description": "Link text for a \"link\" type property.",
+ "type": "string"
+ }
+ },
+ "required": ["name", "desc"],
+ "additionalProperties": false
+ }
+ },
+ "aceCategories": {
+ "description": "Language strings for action/condition/expression categories.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "Language string for an action/condition/expression category.",
+ "type": "string"
+ }
+ },
+ "conditions": {
+ "type": "object",
+ "additionalProperties": { "$ref": "#/$defs/acEntry" }
+ },
+ "actions": {
+ "type": "object",
+ "additionalProperties": { "$ref": "#/$defs/acEntry" }
+ },
+ "expressions": {
+ "type": "object",
+ "additionalProperties": { "$ref": "#/$defs/expEntry" }
+ }
+ },
+ "required": ["name", "description", "help-url"]
+ },
+ "minProperties": 1,
+ "maxProperties": 1
+ }
+ },
+ "required": ["plugins"],
+ "additionalProperties": false
+ }
+ },
+ "required": ["languageTag", "text"],
+ "$defs": {
+ "acEntry": {
+ "description": "Language strings for conditions or actions by their ID.",
+ "type": "object",
+ "properties": {
+ "list-name": {
+ "description": "The name that appears in the condition/action picker dialog.",
+ "type": "string"
+ },
+ "display-text": {
+ "description": "The text that appears in the event sheet. You can use simple BBCode tags like [b] and [i], and use {0}, {1} etc. as parameter placeholders.",
+ "type": "string"
+ },
+ "description": {
+ "description": "A description of the action or condition, which appears as a tip at the top of the condition/action picker dialog.",
+ "type": "string"
+ },
+ "params": {
+ "description": "Language strings for parameters of a condition or action.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "Language strings for a parameter of a condition or action by the parameter ID.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Language string for a parameter name.",
+ "type": "string"
+ },
+ "desc": {
+ "description": "Language string for a parameter description.",
+ "type": "string"
+ },
+ "items": {
+ "$ref": "#/$defs/comboItems"
+ }
+ },
+ "required": ["name", "desc"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["list-name", "display-text", "description"],
+ "additionalProperties": false
+ },
+ "expEntry": {
+ "description": "Language strings for expressions by their ID.",
+ "type": "object",
+ "properties": {
+ "description": {
+ "description": "A description of the action or condition, which appears as a tip at the top of the condition/action picker dialog.",
+ "type": "string"
+ },
+ "translated-name": {
+ "description": "The translated name of the expression, which must be a valid expression identifier (e.g. no quotes/apostrophes or other characters with special meaning in expressions). Note for en-US this must match the expression name."
+ },
+ "params": {
+ "description": "Language strings for parameters of an expression.",
+ "type": "object",
+ "additionalProperties": {
+ "description": "Language strings for a parameter of an expression by the parameter ID.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Language string for a parameter name.",
+ "type": "string"
+ },
+ "desc": {
+ "description": "Language string for a parameter description.",
+ "type": "string"
+ }
+ },
+ "required": ["name", "desc"],
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["description", "translated-name"],
+ "additionalProperties": false
+ },
+ "comboItems": {
+ "description": "Items for a combo property, parameter or group.",
+ "type": "object",
+ "minProperties": 1,
+ "additionalProperties": {
+ "description": "Language string for a combo item, with the item ID as the key.",
+ "type": "string"
+ }
+ },
+ "comboItemGroups": {
+ "description": "Items for a combo-grouped parameter.",
+ "type": "object",
+ "minProperties": 1,
+ "additionalProperties": {
+ "description": "Language string for a combo item group.",
+ "type": "object",
+ "properties": {
+ "name": {
+ "description": "Name of this combo item group.",
+ "type": "string"
+ },
+ "items": {
+ "$ref": "#/$defs/comboItems"
+ }
+ },
+ "required": ["name", "items"]
+ }
+ }
+ }
+}
+
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/spine.d.ts b/spine-ts/spine-construct3/spine.d.ts
new file mode 100644
index 000000000..127e5e8b6
--- /dev/null
+++ b/spine-ts/spine-construct3/spine.d.ts
@@ -0,0 +1,7 @@
+import type * as Spine from '@esotericsoftware/spine-construct3-lib';
+
+declare global {
+ namespace globalThis {
+ var spine: typeof Spine;
+ }
+}
diff --git a/spine-ts/spine-construct3/src/aces.json b/spine-ts/spine-construct3/src/aces.json
new file mode 100644
index 000000000..4c973e949
--- /dev/null
+++ b/spine-ts/spine-construct3/src/aces.json
@@ -0,0 +1,85 @@
+{
+ "$schema": "../aces.schema.json",
+
+ "custom": {
+ "conditions": [
+ {
+ "id": "on-skeleton-loaded",
+ "scriptName": "OnSkeletonLoaded",
+ "isTrigger": true
+ },
+ {
+ "id": "on-animation-event",
+ "scriptName": "OnAnimationEvent",
+ "isTrigger": true,
+ "params": [
+ {
+ "id": "event",
+ "type": "string",
+ "initial-value": "complete"
+ },
+ {
+ "id": "track",
+ "type": "number",
+ "initial-value": 0
+ },
+ {
+ "id": "animation",
+ "type": "string"
+ }
+ ]
+ }
+ ],
+ "actions": [
+ {
+ "id": "do-alert",
+ "scriptName": "Alert",
+ "highlight": true
+ },
+ {
+ "id": "set-skin",
+ "scriptName": "SetSkin",
+ "highlight": false,
+ "params": [
+ {
+ "id": "skin-name",
+ "type": "string"
+ }
+ ]
+ },
+ {
+ "id": "set-animation",
+ "scriptName": "SetAnimation",
+ "highlight": false,
+ "params": [
+ {
+ "id": "track",
+ "type": "number"
+ },
+ {
+ "id": "animation",
+ "type": "string"
+ },
+ {
+ "id": "loop",
+ "type": "boolean"
+ }
+ ]
+ }
+ ],
+ "expressions": [
+ {
+ "id": "double",
+ "expressionName": "Double",
+ "highlight": true,
+ "returnType": "number",
+ "params": [
+ {
+ "id": "number",
+ "type": "number"
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/spine-ts/spine-construct3/src/addon.json b/spine-ts/spine-construct3/src/addon.json
new file mode 100644
index 000000000..1bc197545
--- /dev/null
+++ b/spine-ts/spine-construct3/src/addon.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "./plugin.addon.schema.json",
+
+ "is-c3-addon": true,
+ "sdk-version": 2,
+ "min-construct-version": "r401",
+ "type": "plugin",
+ "name": "My Spine plugin",
+ "id": "EsotericSoftware_SpineConstruct3",
+ "version": "1.0.0.1",
+ "author": "Esoteric Software",
+ "website": "https://www.esotericsoftware.com",
+ "documentation": "https://www.esotericsoftware.com",
+ "description": "Example custom drawing Construct 3 plugin.",
+ "editor-scripts": [
+ "plugin.js",
+ "type.js",
+ "instance.js",
+ "c3runtime/spine-construct3-lib.js"
+ ],
+ "file-list": [
+ "c3runtime/main.js",
+ "c3runtime/plugin.js",
+ "c3runtime/type.js",
+ "c3runtime/instance.js",
+ "c3runtime/conditions.js",
+ "c3runtime/actions.js",
+ "c3runtime/expressions.js",
+ "lang/en-US.json",
+ "aces.json",
+ "addon.json",
+ "icon.svg",
+ "plugin.js",
+ "c3runtime/spine-construct3-lib.js",
+ "type.js",
+ "instance.js"
+ ]
+}
diff --git a/spine-ts/spine-construct3/src/c3runtime/actions.ts b/spine-ts/spine-construct3/src/c3runtime/actions.ts
new file mode 100644
index 000000000..bcfd56db7
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/actions.ts
@@ -0,0 +1,20 @@
+
+import type { SDKInstanceClass } from "./instance.ts";
+
+const C3 = globalThis.C3;
+
+C3.Plugins.EsotericSoftware_SpineConstruct3.Acts =
+{
+ Alert (this: SDKInstanceClass) {
+ alert("Test property = " + this._getTestProperty());
+ },
+
+ SetSkin (this: SDKInstanceClass, skinList: string) {
+ this.setSkin(skinList.split(","));
+ },
+
+ SetAnimation (this: SDKInstanceClass, track: number, animation: string, loop = false) {
+ this.setAnimation(track, animation, loop);
+ }
+
+};
diff --git a/spine-ts/spine-construct3/src/c3runtime/conditions.ts b/spine-ts/spine-construct3/src/c3runtime/conditions.ts
new file mode 100644
index 000000000..5f0c5cb63
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/conditions.ts
@@ -0,0 +1,19 @@
+
+import type { SDKInstanceClass } from "./instance.ts";
+
+const C3 = globalThis.C3;
+
+C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds =
+{
+ OnSkeletonLoaded (this: SDKInstanceClass) {
+ return true;
+ },
+ OnAnimationEvent (this: SDKInstanceClass, event: string, track: number, animation: string) {
+ console.log(this.triggeredEventName === event
+ && this.triggeredEventTrack === track
+ && this.triggeredEventAnimation === animation);
+ return this.triggeredEventName === event
+ && this.triggeredEventTrack === track
+ && this.triggeredEventAnimation === animation;
+ },
+};
diff --git a/spine-ts/spine-construct3/src/c3runtime/expressions.ts b/spine-ts/spine-construct3/src/c3runtime/expressions.ts
new file mode 100644
index 000000000..8273fc11d
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/expressions.ts
@@ -0,0 +1,13 @@
+
+import type { SDKInstanceClass } from "./instance.ts";
+
+const C3 = globalThis.C3;
+
+C3.Plugins.EsotericSoftware_SpineConstruct3.Exps =
+{
+ Double(this: SDKInstanceClass, num: number)
+ {
+ return num * 2;
+ }
+};
+
diff --git a/spine-ts/spine-construct3/src/c3runtime/instance.ts b/spine-ts/spine-construct3/src/c3runtime/instance.ts
new file mode 100644
index 000000000..ff749dbd5
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/instance.ts
@@ -0,0 +1,289 @@
+import { AnimationEventType, AnimationStateListener, BlendingModeSpineToC3, EventType, TrackEntry, type AnimationState, type AssetLoader, type Event, type Skeleton, type SkeletonRendererCore, type SpineBoundsProvider, type TextureAtlas } from "@esotericsoftware/spine-construct3-lib";
+
+const C3 = globalThis.C3;
+const spine = globalThis.spine;
+
+spine.Skeleton.yDown = true;
+
+class DrawingInstance extends globalThis.ISDKWorldInstanceBase {
+ atlasProp = "";
+ skelProp = "";
+ skinProp: string[] = [];
+ animationProp?: string;
+
+ textureAtlas?: TextureAtlas;
+ renderer?: IRenderer;
+ atlasLoaded = false;
+ atlasLoading = false;
+ skeletonLoaded = false;
+ skeletonLoading = false;
+ skeleton?: Skeleton;
+ state?: AnimationState;
+
+ private ratio: number;
+
+ private assetLoader: AssetLoader;
+ private skeletonRenderer: SkeletonRendererCore;
+ private spineBoundsProvider: SpineBoundsProvider;
+ private _spineBounds?: {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+ };
+
+ constructor () {
+ super();
+
+ const properties = this._getInitProperties();
+ if (properties) {
+ this.atlasProp = properties[0] as string;
+ this.skelProp = properties[1] as string;
+ const skinProp = properties[2] as string;
+ this.skinProp = skinProp === "" ? [] : skinProp.split(",");
+ this.animationProp = properties[3] as string;
+ console.log(properties);
+ }
+
+ this.assetLoader = new spine.AssetLoader("runtime");
+ this.skeletonRenderer = new spine.SkeletonRendererCore();
+
+ if (this.animationProp || (this.skinProp && this.skinProp.length > 0)) {
+ this.spineBoundsProvider = new spine.SkinsAndAnimationBoundsProvider(this.animationProp, this.skinProp);
+ } else {
+ this.spineBoundsProvider = new spine.SetupPoseBoundsProvider();
+ }
+
+ this.ratio = this.width / this.height;
+
+ this._setTicking(true);
+ }
+
+ _tick (): void {
+ const { renderer } = this;
+
+ if (!renderer) return;
+
+ if (!this.atlasLoaded) {
+ this._loadAtlas();
+ return;
+ }
+
+ if (!this.skeletonLoaded) {
+ this.loadSkeleton();
+ return;
+ }
+
+ this.x++;
+ this.x--;
+ this.update(this.dt);
+ }
+
+ private async loadSkeleton () {
+ if (this.skeletonLoading) return;
+ if (!this.atlasLoaded) return;
+ this.skeletonLoading = true;
+
+ const propValue = this.skelProp;
+
+ if (this.atlasLoaded && this.textureAtlas) {
+ const skeletonData = await this.assetLoader.loadSkeletonRuntime(propValue, this.textureAtlas, 0.25, this.plugin.runtime);
+ if (!skeletonData) return;
+
+ this.skeleton = new spine.Skeleton(skeletonData);
+ const animationStateData = new spine.AnimationStateData(skeletonData);
+ this.state = new spine.AnimationState(animationStateData);
+
+ if (this.animationProp) {
+ this.setAnimation(0, this.animationProp, true);
+ }
+
+ this._setSkin();
+
+ this.update(0);
+
+ this._spineBounds = this.spineBoundsProvider.calculateBounds(this);
+
+ // Initially, width and height are values set on C3 Editor side that allows to determine the right scale
+ this.skeleton.scaleX = this.width / this._spineBounds.width;
+ this.skeleton.scaleY = this.height / this._spineBounds.height;
+
+ this.setSize(this._spineBounds.width * this.skeleton.scaleX, this._spineBounds.height * -this.skeleton.scaleY);
+ this.setOrigin(-this._spineBounds.x * this.skeleton.scaleX / this.width, this._spineBounds.y * this.skeleton.scaleY / this.height);
+
+
+ this.skeletonLoaded = true;
+ this._trigger(C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds.OnSkeletonLoaded);
+ }
+ }
+
+ public triggeredEventTrack = -1;
+ public triggeredEventAnimation = "";
+ public triggeredEventName = "";
+ public triggeredEventData?: Event;
+
+ private triggetAnimationEvent (eventName: string, track: number, animation: string, event?: Event) {
+ this.triggeredEventTrack = track;
+ this.triggeredEventAnimation = animation;
+ this.triggeredEventName = eventName;
+ this.triggeredEventData = event;
+ this._trigger(C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds.OnAnimationEvent);
+ }
+ public setAnimation (track: number, animation: string, loop = false) {
+ const trackEntry = this.state?.setAnimation(track, animation, loop);
+ if (!trackEntry) return;
+
+ trackEntry.listener = {
+ start: () => {
+ this.triggetAnimationEvent("start", track, animation);
+ },
+ dispose: () => {
+ this.triggetAnimationEvent("dispose", track, animation);
+ },
+ event: (_, event) => {
+ this.triggetAnimationEvent("event", track, animation, event);
+ },
+ interrupt: () => {
+ this.triggetAnimationEvent("interrupt", track, animation);
+ },
+ end: () => {
+ this.triggetAnimationEvent("end", track, animation);
+ },
+ complete: () => {
+ this.triggetAnimationEvent("complete", track, animation);
+ },
+ }
+ }
+
+ public setSkin (skins: string[]) {
+ this.skinProp = skins;
+ this._setSkin();
+ }
+
+ private _setSkin () {
+ const { skeleton } = this;
+ if (!skeleton) return;
+
+ const skins = this.skinProp;
+
+ if (skins.length === 0) {
+ skeleton.skin = null;
+ } else if (skins.length === 1) {
+ const skinName = skins[0];
+ const skin = skeleton.data.findSkin(skinName);
+ if (!skin) {
+ // TODO: signal error
+ return;
+ }
+ skeleton.setSkin(skins[0]);
+ } else {
+ const customSkin = new spine.Skin(skins.join(","));
+ for (const s of skins) {
+ const skin = skeleton.data.findSkin(s)
+ if (!skin) {
+ // TODO: signal error
+ return;
+ }
+ customSkin.addSkin(skin);
+ }
+ skeleton.setSkin(customSkin);
+ }
+
+ skeleton.setupPose();
+ this.update(0);
+ }
+
+ private update (delta: number) {
+ const { state, skeleton } = this;
+
+ if (!skeleton || !state) return;
+
+ state.update(delta);
+ skeleton.update(delta);
+ state.apply(skeleton);
+ skeleton.updateWorldTransform(spine.Physics.update);
+ }
+
+ private async _loadAtlas () {
+ if (this.atlasLoading || !this.renderer) return;
+ this.atlasLoading = true;
+
+ const textureAtlas = await this.assetLoader.loadAtlasRuntime(this.atlasProp, this.plugin.runtime, this.renderer);
+ if (!textureAtlas) return;
+
+ this.textureAtlas = textureAtlas;
+ this.atlasLoaded = true;
+ }
+
+ _release () {
+ super._release();
+ }
+
+ private tempVertices = new Float32Array(4096);
+ private tempColors = new Float32Array(4096);
+ _draw (renderer: IRenderer) {
+ this.renderer ||= renderer;
+
+ if (!this.isVisible) return;
+ if (!this.isOnScreen) return;
+ if (!this.skeleton) return;
+
+ let command = this.skeletonRenderer.render(this.skeleton);
+ const inv255 = 1 / 255;
+ while (command) {
+ const { numVertices, positions, uvs, colors, indices, numIndices, blendMode } = command;
+
+ const vertices = this.tempVertices;
+ const c3colors = this.tempColors;
+ for (let i = 0; i < numVertices; i++) {
+ const srcIndex = i * 2;
+ const dstIndex = i * 3;
+ vertices[dstIndex] = positions[srcIndex] + this.x;
+ vertices[dstIndex + 1] = positions[srcIndex + 1] + this.y;
+ vertices[dstIndex + 2] = 0;
+
+ // there's something wrong with the hand after adding the colors on spineboy portal animation
+ const color = colors[i];
+ const colorDst = i * 4;
+ c3colors[colorDst] = (color >>> 16 & 0xFF) * inv255;
+ c3colors[colorDst + 1] = (color >>> 8 & 0xFF) * inv255;
+ c3colors[colorDst + 2] = (color & 0xFF) * inv255;
+ c3colors[colorDst + 3] = (color >>> 24 & 0xFF) * inv255 * this.opacity;
+ }
+
+ renderer.setTexture(command.texture.texture);
+ renderer.setBlendMode(spine.BlendingModeSpineToC3[blendMode]);
+ renderer.drawMesh(
+ vertices.subarray(0, numVertices * 3),
+ uvs.subarray(0, numVertices * 2),
+ indices.subarray(0, numIndices),
+ c3colors.subarray(0, numVertices * 4),
+ );
+
+ command = command.next;
+ }
+
+ }
+
+ _saveToJson () {
+ return {
+ // data to be saved for savegames
+ };
+ }
+
+ _loadFromJson (o: JSONValue) {
+ // load state for savegames
+ }
+
+ _setTestProperty (n: number) {
+ // this._testProperty = n;
+ }
+
+ _getTestProperty () {
+ // return this._testProperty;
+ }
+};
+
+C3.Plugins.EsotericSoftware_SpineConstruct3.Instance = DrawingInstance;
+
+export type { DrawingInstance as SDKInstanceClass };
diff --git a/spine-ts/spine-construct3/src/c3runtime/main.ts b/spine-ts/spine-construct3/src/c3runtime/main.ts
new file mode 100644
index 000000000..d4e0944b2
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/main.ts
@@ -0,0 +1,6 @@
+import "./plugin.js";
+import "./type.js";
+import "./instance.js";
+import "./conditions.js";
+import "./actions.js";
+import "./expressions.js";
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/src/c3runtime/plugin.ts b/spine-ts/spine-construct3/src/c3runtime/plugin.ts
new file mode 100644
index 000000000..cf426d1b3
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/plugin.ts
@@ -0,0 +1,13 @@
+
+const C3 = globalThis.C3;
+
+C3.Plugins.EsotericSoftware_SpineConstruct3 = class DrawingPlugin extends globalThis.ISDKPluginBase
+{
+ constructor()
+ {
+ super();
+ }
+};
+
+// Necessary for TypeScript to treat this file as a module
+export {}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/src/c3runtime/type.ts b/spine-ts/spine-construct3/src/c3runtime/type.ts
new file mode 100644
index 000000000..ec6593293
--- /dev/null
+++ b/spine-ts/spine-construct3/src/c3runtime/type.ts
@@ -0,0 +1,49 @@
+
+import type { SDKInstanceClass } from "./instance.ts";
+
+const C3 = globalThis.C3;
+
+C3.Plugins.EsotericSoftware_SpineConstruct3.Type = class DrawingType extends globalThis.ISDKObjectTypeBase
+{
+ constructor()
+ {
+ super();
+ }
+
+
+ // async _loadTextures(renderer: IRenderer)
+ // {
+ // return renderer.loadTextureForImageInfo(this.getImageInfo(), {
+ // sampling: this.runtime.sampling
+ // });
+ // }
+
+ // async _loadTextures(renderer: IRenderer)
+ // {
+ // return renderer.loadTextureForImageInfo(this.getImageInfo(), {
+ // sampling: this.runtime.sampling
+ // });
+ // }
+
+ // getImageInfo(): IImageInfo
+ // {
+ // return {
+ // width: 1,
+ // height: 1,
+ // getSize(): Vec2Arr { return [1, 1]; },
+ // getTexture(renderer: IRenderer): ITexture | null { return null; },
+ // getTexRect(): DOMRect { return new DOMRect(0, 0, 1, 1); }
+ // };
+ // }
+
+ // _onCreate()
+ // {
+ // this.runtime.assets.loadImageAsset(this.getImageInfo());
+ // }
+
+
+ // _releaseTextures(renderer: IRenderer)
+ // {
+ // renderer.releaseTextureForImageInfo(this.getImageInfo());
+ // }
+};
diff --git a/spine-ts/spine-construct3/src/icon.svg b/spine-ts/spine-construct3/src/icon.svg
new file mode 100644
index 000000000..911e60e30
--- /dev/null
+++ b/spine-ts/spine-construct3/src/icon.svg
@@ -0,0 +1,37 @@
+
+
+
+
diff --git a/spine-ts/spine-construct3/src/instance.ts b/spine-ts/spine-construct3/src/instance.ts
new file mode 100644
index 000000000..f27afb9d9
--- /dev/null
+++ b/spine-ts/spine-construct3/src/instance.ts
@@ -0,0 +1,383 @@
+// /
+
+import type { AnimationState, AssetLoader, Skeleton, SkeletonRendererCore, SpineBoundsProvider, TextureAtlas } from "@esotericsoftware/spine-construct3-lib";
+
+const SDK = globalThis.SDK;
+
+const PLUGIN_CLASS = SDK.Plugins.EsotericSoftware_SpineConstruct3;
+
+let spine: typeof globalThis.spine;
+
+type SpineBoundsProviderType = "setup" | "animation-skin" | "AABB";
+
+class MyDrawingInstance extends SDK.IWorldInstanceBase {
+ private layoutView?: SDK.UI.ILayoutView;
+ private renderer?: SDK.Gfx.IWebGLRenderer;
+
+ private currentSkelName = "";
+ private currentAtlasName = "";
+ private textureAtlas?: TextureAtlas;
+
+ skeleton?: Skeleton;
+ state?: AnimationState;
+ skins: string[] = [];
+ currentSkinString?: string;
+ animation?: string;
+
+ private assetLoader: AssetLoader;
+ private skeletonRenderer: SkeletonRendererCore;
+
+ private offsetX = 0;
+ private offsetY = 0;
+ private offsetWidth = 0;
+ private offsetHeight = 0;
+ private positioningBounds = false;
+ private spineBoundsProviderType: SpineBoundsProviderType = "setup";
+ private spineBoundsProvider?: SpineBoundsProvider;
+ private _spineBounds?: {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+ };
+
+ constructor (sdkType: SDK.ITypeBase, inst: SDK.IWorldInstance) {
+ super(sdkType, inst);
+
+ if (!spine) spine = globalThis.spine;
+ spine.Skeleton.yDown = true;
+
+ this.assetLoader = new spine.AssetLoader("editor");
+ this.skeletonRenderer = new spine.SkeletonRendererCore();
+ }
+
+ Release () {
+ }
+
+ OnCreate () {
+ console.log("OnCreate");
+ }
+
+ OnPlacedInLayout () {
+ this.OnMakeOriginalSize();
+ }
+
+ private tempVertices = new Float32Array(4096);
+ Draw (iRenderer: SDK.Gfx.IWebGLRenderer, iDrawParams: SDK.Gfx.IDrawParams) {
+ console.log("DRAW");
+ this.layoutView ||= iDrawParams.GetLayoutView();
+ this.renderer ||= iRenderer;
+
+ this.loadAtlas();
+ this.loadSkeleton();
+
+ if (this.skeleton) {
+ this.setSkin();
+
+ let x = this.overallOffsetX;
+ let y = this.overallOffsetY;
+
+ let width = this.offsetWidth;
+ let height = this.offsetHeight;
+
+ if (!this.positioningBounds) {
+ x += this._inst.GetX();
+ y += this._inst.GetY();
+ width = this._inst.GetWidth();
+ height = this._inst.GetHeight();
+ } else {
+ // x += this._inst.GetX();
+ // y += this._inst.GetY();
+ // width += this._inst.GetWidth();
+ // height += this._inst.GetHeight();
+ }
+
+ const rx = width / this._spineBounds!.width;
+
+ console.log(width, this._spineBounds!.width, rx);
+
+ const ry = height / this._spineBounds!.height;
+ this.skeleton.scaleX = rx;
+ this.skeleton.scaleY = ry;
+
+ this.update(0);
+
+ let command = this.skeletonRenderer.render(this.skeleton);
+ while (command) {
+ const { numVertices, positions, uvs, indices, numIndices } = command;
+
+ const vertices = this.tempVertices;
+ for (let i = 0; i < numVertices; i++) {
+ const srcIndex = i * 2;
+ const dstIndex = i * 3;
+ vertices[dstIndex] = positions[srcIndex] + x;
+ vertices[dstIndex + 1] = positions[srcIndex + 1] + y;
+ vertices[dstIndex + 2] = 0;
+ }
+
+ iRenderer.SetAlphaBlend();
+ iRenderer.SetTexture(command.texture.texture);
+
+ iRenderer.DrawMesh(
+ vertices.subarray(0, numVertices * 3),
+ uvs.subarray(0, numVertices * 2),
+ indices.subarray(0, numIndices),
+ );
+
+ command = command.next;
+ }
+
+ // iRenderer.SetAlphaBlend();
+ // iRenderer.SetColorFillMode();
+ // iRenderer.SetColorRgba(0.25, 0, 0, 0.25);
+ // iRenderer.LineRect(this._inst.GetX(), this._inst.GetY(), this._inst.GetWidth(), this._inst.GetHeight());
+
+ } else {
+ // render placeholder
+ iRenderer.SetAlphaBlend();
+ iRenderer.SetColorFillMode();
+
+ if (this.HadTextureError())
+ iRenderer.SetColorRgba(0.25, 0, 0, 0.25);
+ else
+ iRenderer.SetColorRgba(0, 0, 0.1, 0.1);
+
+ iRenderer.Quad(this._inst.GetQuad());
+ }
+ }
+
+ private overallOffsetX = 0;
+ private overallOffsetY = 0;
+ private overallScaleX = 1
+ async OnPropertyChanged (id: string, value: EditorPropertyValueType) {
+ console.log("Prop change - Name: " + id + " - Value: " + value);
+
+ switch (id) {
+ case PLUGIN_CLASS.PROP_ATLAS:
+ this.layoutView?.Refresh();
+ break;
+ case PLUGIN_CLASS.PROP_SKELETON:
+ this.layoutView?.Refresh();
+ break;
+ case PLUGIN_CLASS.PROP_SKIN:
+ this.layoutView?.Refresh();
+ break;
+ case PLUGIN_CLASS.PROP_ANIMATION:
+ this.layoutView?.Refresh();
+ break;
+ case PLUGIN_CLASS.PROP_BOUNDS_PROVIDER:
+ this.setC3Bounds(true);
+ this.layoutView?.Refresh();
+ break;
+ case PLUGIN_CLASS.PROP_BOUNDS_PROVIDER_MOVE:
+ value = value as boolean
+ if (value) {
+ this.overallOffsetX += this._inst.GetX();
+ this.overallOffsetY += this._inst.GetY();
+ this.offsetX = this._inst.GetX();
+ this.offsetY = this._inst.GetY();
+ this.offsetWidth = this._inst.GetWidth();
+ this.offsetHeight = this._inst.GetHeight();
+ } else {
+ const w = this.offsetWidth;
+
+ this.overallOffsetX -= this._inst.GetX();
+ this.overallOffsetY -= this._inst.GetY();
+ this.offsetX -= this._inst.GetX();
+ this.offsetY -= this._inst.GetY();
+ this.offsetWidth -= this._inst.GetWidth();
+ this.offsetHeight -= this._inst.GetHeight();
+
+
+
+ console.log("OFFSETS");
+ console.log(this.offsetX);
+ console.log(this.offsetY);
+ console.log(this.overallOffsetX);
+ console.log(this.overallOffsetY);
+ console.log("OFFSETS");
+
+
+ this.spineBoundsProvider = new spine.AABBRectangleBoundsProvider(
+ this._spineBounds!.x - this.offsetX,
+ this._spineBounds!.y - this.offsetY,
+ this._spineBounds!.width - this.offsetWidth,
+ this._spineBounds!.height - this.offsetHeight,
+ );
+
+ this._spineBounds = this.spineBoundsProvider.calculateBounds(this);
+ const { x, y, width, height } = this._spineBounds;
+
+ console.log(this._inst.GetX(), this._inst.GetY());
+ console.log(x, y, width, height, (-x) / width, (-y) / height);
+
+ // this._inst.SetSize(width, height);
+ // this._inst.SetOrigin(-x / width, -y / height);
+
+ }
+ this.positioningBounds = value;
+ break;
+ }
+
+ console.log("Prop change end");
+ }
+
+ private setSkin () {
+ const { skeleton } = this;
+ if (!skeleton) return;
+
+ const propValue = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKIN) as string;
+
+ if (this.currentSkinString === propValue) return;
+ this.currentSkinString = propValue;
+
+ const skins = propValue === "" ? [] : propValue.split(",");
+ this.skins = skins;
+
+ if (skins.length === 1) {
+ const skinName = skins[0];
+ const skin = skeleton.data.findSkin(skinName);
+ if (!skin) {
+ // TODO: signal error
+ return;
+ }
+ skeleton.setSkin(skins[0]);
+ } else if (skins.length > 1) {
+ const customSkin = new spine.Skin(propValue);
+ for (const s of skins) {
+ const skin = skeleton.data.findSkin(s)
+ if (!skin) {
+ // TODO: signal error
+ return;
+ }
+ customSkin.addSkin(skin);
+ }
+ skeleton.setSkin(customSkin);
+ }
+
+ skeleton.setupPose();
+ this.update(0);
+
+ this.setC3Bounds();
+ }
+
+ private async loadSkeleton () {
+ const propValue = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON) as string;
+ const projectFile = this._inst.GetProject().GetProjectFileByName(propValue);
+
+ if (projectFile && this.textureAtlas) {
+ if (this.currentSkelName === propValue) return;
+ this.currentSkelName = propValue;
+
+ const skeletonData = await this.assetLoader.loadSkeletonEditor(propValue, this.textureAtlas, this._inst);
+ if (!skeletonData) return;
+
+ this.skeleton = new spine.Skeleton(skeletonData);
+ const animationStateData = new spine.AnimationStateData(skeletonData);
+ this.state = new spine.AnimationState(animationStateData);
+
+ this.update(0);
+
+ this.setSkin();
+ this.setC3Bounds(true);
+
+ console.log("SKELETON LOADED");
+ }
+ }
+
+ private setC3Bounds (init = false) {
+ const propValue = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_PROVIDER) as SpineBoundsProviderType;
+
+ console.log(propValue);
+
+ if (propValue === "animation-skin") {
+ const { skins, animation } = this;
+ if ((skins && skins.length > 0) || animation) {
+ this.spineBoundsProvider = new spine.SkinsAndAnimationBoundsProvider(animation, skins);
+ } else {
+ throw new Error("One among skin and animation needs to have a value to set this bounds provider.");
+ }
+ } else if (propValue === "setup") {
+ this.spineBoundsProvider = new spine.SetupPoseBoundsProvider();
+ } else {
+ this.spineBoundsProvider = new spine.AABBRectangleBoundsProvider(0, 0, 100, 100);
+ }
+
+
+
+ this._spineBounds = this.spineBoundsProvider.calculateBounds(this);
+
+ const { x, y, width, height } = this._spineBounds;
+
+ if (width <= 0 || height <= 0 || !init) return;
+
+ this._inst.SetSize(width, height);
+ this._inst.SetOrigin(-x / width, -y / height);
+ }
+
+ private update (delta: number) {
+ const { state, skeleton } = this;
+
+ if (!skeleton || !state) return;
+
+ state.update(delta);
+ skeleton.update(delta);
+ state.apply(skeleton);
+ skeleton.updateWorldTransform(spine.Physics.update);
+ }
+
+ private async loadAtlas () {
+ if (!this.renderer) return;
+
+ const propValue = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_ATLAS) as string;
+
+ if (this.currentAtlasName === propValue) return;
+ this.currentAtlasName = propValue;
+
+ const textureAtlas = await this.assetLoader.loadAtlasEditor(propValue, this._inst, this.renderer);
+ if (!textureAtlas) return;
+
+ this.textureAtlas = textureAtlas;
+ this.layoutView?.Refresh();
+ }
+
+ GetTexture () {
+ const image = this.GetObjectType().GetImage();
+ return super.GetTexture(image);
+ }
+
+ IsOriginalSizeKnown () {
+ return true;
+ }
+
+ GetOriginalWidth () {
+ if (!this._spineBounds) return 100;
+ return this._spineBounds.width;
+ }
+
+ GetOriginalHeight () {
+ if (!this._spineBounds) return 100;
+ return this._spineBounds.height;
+ }
+
+ OnMakeOriginalSize () {
+ if (!this._spineBounds)
+ this._inst.SetSize(100, 100);
+ else
+ this._inst.SetSize(this._spineBounds.width, this._spineBounds.height);
+ }
+
+ HasDoubleTapHandler () {
+ return false;
+ }
+
+ OnDoubleTap () { }
+
+ LoadC2Property (name: string, valueString: string) {
+ return false; // not handled
+ }
+};
+
+PLUGIN_CLASS.Instance = MyDrawingInstance;
+
+export type { MyDrawingInstance as SDKEditorInstanceClass };
diff --git a/spine-ts/spine-construct3/src/lang/en-US.json b/spine-ts/spine-construct3/src/lang/en-US.json
new file mode 100644
index 000000000..ff53a7f39
--- /dev/null
+++ b/spine-ts/spine-construct3/src/lang/en-US.json
@@ -0,0 +1,132 @@
+{
+ "$schema": "../../plugin.lang.schema.json",
+
+ "languageTag": "en-US",
+ "fileDescription": "Strings for MyDrawingPlugin.",
+ "text": {
+ "plugins": {
+ "esotericsoftware_spineconstruct3": {
+ "name": "Spine",
+ "description": "Spine runtime for Construct3.",
+ "help-url": "https://www.construct.net",
+ "properties": {
+ "spine-skeleton-file": {
+ "name": "Skeleton",
+ "desc": "Skeleton file"
+ },
+ "spine-atlas-file": {
+ "name": "Atlas",
+ "desc": "Atlas file"
+ },
+ "spine-skeleton-file-blob": {
+ "name": "Skel Blob",
+ "desc": "Skel file blob"
+ },
+ "spine-animation": {
+ "name": "animation",
+ "desc": "animation"
+ },
+ "spine-skin": {
+ "name": "skin",
+ "desc": "skin"
+ },
+ "spine-bounds-provider-group": {
+ "name": "Bounds provider",
+ "desc": "Select the desired buound provider and fill the respective properties."
+ },
+ "spine-bounds-provider": {
+ "name": "Bounds provider",
+ "desc": "The bounds provider to use.",
+ "items": {
+ "AABB": "AABB Rectangle",
+ "setup": "Setup pose bounds",
+ "animation-skin": "Animation + Skin bounds"
+ }
+ },
+ "spine-bounds-provider-move": {
+ "name": "Position bounds",
+ "desc": "Keep the skeleton in a fixed position while adjusting the size and position of the bounds."
+ }
+ },
+ "aceCategories": {
+ "custom": "Custom"
+ },
+ "conditions": {
+ "on-skeleton-loaded": {
+ "list-name": "On skeleton loaded",
+ "display-text": "On skeleton loaded",
+ "description": "Do something when skeleton is loaded"
+ },
+ "on-animation-event": {
+ "list-name": "On animation event",
+ "display-text": "On {0} event triggered by animation {2} on track {1} trigger",
+ "description": "Do something when animation event is triggered",
+ "params": {
+ "event": {
+ "name": "Event name",
+ "desc": "Event name"
+ },
+ "animation": {
+ "name": "Animation",
+ "desc": "Animation"
+ },
+ "track": {
+ "name": "Track number",
+ "desc": "Track number"
+ }
+ }
+ }
+ },
+ "actions": {
+ "do-alert": {
+ "list-name": "Do alert",
+ "display-text": "Do alert",
+ "description": "Do a dummy alert."
+ },
+ "set-skin": {
+ "list-name": "Set skin",
+ "display-text": "Set skin {0}",
+ "description": "Set skin",
+ "params": {
+ "skin-name": {
+ "name": "Skins list",
+ "desc": "A comma separated list of skins to set. Empty string to unset skins."
+ }
+ }
+ },
+ "set-animation": {
+ "list-name": "Set animation",
+ "display-text": "Set animation {1} on track {0} with loop {2}",
+ "description": "Set animation",
+ "params": {
+ "track": {
+ "name": "track",
+ "desc": "track"
+ },
+ "animation": {
+ "name": "animations name",
+ "desc": "animations name"
+ },
+ "loop": {
+ "name": "loop",
+ "desc": "loop"
+ }
+ }
+ }
+ },
+ "expressions": {
+ "double": {
+ "description": "Double a number.",
+ "translated-name": "Double",
+ "params": {
+ "number": {
+ "name": "Number",
+ "desc": "The number to double."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/spine-ts/spine-construct3/src/plugin.addon.schema.json b/spine-ts/spine-construct3/src/plugin.addon.schema.json
new file mode 100644
index 000000000..bdb338a3a
--- /dev/null
+++ b/spine-ts/spine-construct3/src/plugin.addon.schema.json
@@ -0,0 +1,73 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://construct.net/sdk/schema/plugin.addon.schema.json",
+ "title": "Plugin addon.json",
+ "description": "Main JSON file that describes metadata about a plugin.",
+ "type": "object",
+ "properties": {
+ "is-c3-addon": {
+ "description": "This is used by Construct to identify valid addons.",
+ "const": true
+ },
+ "sdk-version": {
+ "description": "The version of the Addon SDK used for this addon.",
+ "enum": [1, 2]
+ },
+ "type": {
+ "description": "Indicates the addon type. For the plugin schema, this must be \"plugin\".",
+ "const": "plugin"
+ },
+ "name": {
+ "description": "The displayed name of the addon, in English. This can be changed after release.",
+ "type": "string"
+ },
+ "id": {
+ "description": "The unique ID of the addon. This must not be used by any other addon ever published for Construct, and must never change after you first publish your addon. It is recommended to use a vendor-specific prefix, e.g. MyCompany_MyAddon.",
+ "type": "string"
+ },
+ "version": {
+ "description": "A string specifying the addon version in four parts (major, minor, patch, revision).",
+ "type": "string"
+ },
+ "min-construct-version": {
+ "description": "The minimum Construct version required to use this addon, e.g. \"r400\"",
+ "type": "string"
+ },
+ "supports-worker-mode": {
+ "description": "Whether the addon supports running in worker mode, where the Construct runtime is hosted in a Web Worker. Defaults to true; if set to false the presence of the addon in a project will block the runtime from using worker mode.",
+ "type": "boolean"
+ },
+ "author": {
+ "description": "A string identifying the author of the addon.",
+ "type": "string"
+ },
+ "website": {
+ "description": "A string of a URL to the author's website. It is recommended to provide updates to the addon at this URL if any become available. The website should use HTTPS.",
+ "type": "string",
+ "format": "uri"
+ },
+ "documentation": {
+ "description": "A string of a URL to the online documentation for the addon. It is important to provide documentation for your addon to be useful to users.",
+ "type": "string",
+ "format": "uri"
+ },
+ "description": {
+ "description": "A string of a brief description of what the addon does, displayed when prompting the user to install the addon.",
+ "type": "string"
+ },
+ "editor-scripts": {
+ "description": "An array of script files in the addon package to load in the editor.",
+ "type": "array",
+ "items": { "type": "string" },
+ "minItems": 1,
+ "uniqueItems": true
+ },
+ "file-list": {
+ "description": "A list of all files used by the addon. Required for Developer Mode addons to work.",
+ "type": "array",
+ "items": { "type": "string" }
+ }
+ },
+ "required": ["is-c3-addon", "type", "name", "id", "version", "author", "website", "documentation", "description", "editor-scripts"]
+}
+
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/src/plugin.ts b/spine-ts/spine-construct3/src/plugin.ts
new file mode 100644
index 000000000..b0bd067e3
--- /dev/null
+++ b/spine-ts/spine-construct3/src/plugin.ts
@@ -0,0 +1,113 @@
+import type { SDKEditorInstanceClass } from "./instance.ts";
+
+const SDK = globalThis.SDK;
+
+////////////////////////////////////////////
+// The plugin ID is how Construct identifies different kinds of plugins.
+// *** NEVER CHANGE THE PLUGIN ID! ***
+// If you change the plugin ID after releasing the plugin, Construct will think it is an entirely different
+// plugin and assume it is incompatible with the old one, and YOU WILL BREAK ALL EXISTING PROJECTS USING THE PLUGIN.
+// Only the plugin name is displayed in the editor, so to rename your plugin change the name but NOT the ID.
+// If you want to completely replace a plugin, make it deprecated (it will be hidden but old projects keep working),
+// and create an entirely new plugin with a different plugin ID.
+const PLUGIN_ID = "EsotericSoftware_SpineConstruct3";
+////////////////////////////////////////////
+
+const PLUGIN_CATEGORY = "general";
+
+let app = null;
+
+const PLUGIN_CLASS = class MyDrawingPlugin extends SDK.IPluginBase {
+ static PROP_ATLAS = "spine-atlas-file";
+ static PROP_SKELETON = "spine-skeleton-file";
+ static PROP_SKIN = "spine-skin";
+ static PROP_ANIMATION = "spine-animation";
+ static PROP_ERRORS = "spine-errors";
+ static PROP_RATIO_WIDTH = "spine-restore-ratio-width";
+ static PROP_RATIO_HEIGHT = "spine-restore-ratio-height";
+ static PROP_SKELETON_BLOB = "spine-skeleton-file-blob";
+ static PROP_BOUNDS_PROVIDER_GROUP = "spine-bounds-provider-group";
+ static PROP_BOUNDS_PROVIDER = "spine-bounds-provider";
+ static PROP_BOUNDS_PROVIDER_MOVE = "spine-bounds-provider-move";
+
+ static TYPE_BOUNDS_SETUP = "setup";
+ static TYPE_BOUNDS_ANIMATION_SKIN = "animation-skin";
+ static TYPE_BOUNDS_AABB = "AABB";
+
+ constructor () {
+ super(PLUGIN_ID);
+
+
+ SDK.Lang.PushContext("plugins." + PLUGIN_ID.toLowerCase());
+
+ // @ts-ignore
+ this._info.SetName(globalThis.lang(".name"));
+ // @ts-ignore
+ this._info.SetDescription(globalThis.lang(".description"));
+ this._info.SetCategory(PLUGIN_CATEGORY);
+ this._info.SetAuthor("Esoteric Software");
+ // @ts-ignore
+ this._info.SetHelpUrl(globalThis.lang(".help-url"));
+ this._info.SetPluginType("world"); // mark as world plugin, which can draw
+ this._info.SetIsResizable(true); // allow to be resized
+ this._info.SetIsRotatable(true); // allow to be rotated
+ this._info.SetHasImage(false);
+ this._info.SetSupportsEffects(true); // allow effects
+ this._info.SetMustPreDraw(true);
+ this._info.SetRuntimeModuleMainScript("c3runtime/main.js");
+ this._info.AddC3RuntimeScript("c3runtime/spine-construct3-lib.js");
+ this._info.AddFileDependency({
+ filename: "c3runtime/spine-construct3-lib.js",
+ type: "external-runtime-script"
+ })
+
+ SDK.Lang.PushContext(".properties");
+
+ this._info.SetProperties([
+ new SDK.PluginProperty("text", MyDrawingPlugin.PROP_ATLAS, ""),
+ new SDK.PluginProperty("text", MyDrawingPlugin.PROP_SKELETON, ""),
+ new SDK.PluginProperty("text", MyDrawingPlugin.PROP_SKIN, ""),
+ new SDK.PluginProperty("text", MyDrawingPlugin.PROP_ANIMATION, ""),
+ new SDK.PluginProperty("projectfile", MyDrawingPlugin.PROP_SKELETON_BLOB, ""),
+ new SDK.PluginProperty("info", MyDrawingPlugin.PROP_ERRORS, {
+ infoCallback (inst) {
+ const atlas = inst.GetInstance().GetPropertyValue(MyDrawingPlugin.PROP_ATLAS);
+ const skeleton = inst.GetInstance().GetPropertyValue(MyDrawingPlugin.PROP_SKELETON);
+
+ let error = "";
+ if (atlas && skeleton) {
+ error = "You can't set both .skel and .json skeleton file.";
+ }
+
+ if (!atlas && !skeleton) {
+ error = "Missing skeleton file.";
+ }
+
+ return error;
+ },
+ }),
+
+
+ new SDK.PluginProperty("group", MyDrawingPlugin.PROP_BOUNDS_PROVIDER_GROUP),
+ new SDK.PluginProperty("combo", MyDrawingPlugin.PROP_BOUNDS_PROVIDER, {
+ initialValue: "setup",
+ items: [
+ MyDrawingPlugin.TYPE_BOUNDS_SETUP,
+ MyDrawingPlugin.TYPE_BOUNDS_ANIMATION_SKIN,
+ MyDrawingPlugin.TYPE_BOUNDS_AABB
+ ],
+ }),
+ new SDK.PluginProperty("check", MyDrawingPlugin.PROP_BOUNDS_PROVIDER_MOVE, false),
+
+
+ ]);
+
+ SDK.Lang.PopContext(); // .properties
+
+ SDK.Lang.PopContext();
+ }
+};
+
+SDK.Plugins.EsotericSoftware_SpineConstruct3 = PLUGIN_CLASS;
+
+PLUGIN_CLASS.Register(PLUGIN_ID, PLUGIN_CLASS);
diff --git a/spine-ts/spine-construct3/src/type.ts b/spine-ts/spine-construct3/src/type.ts
new file mode 100644
index 000000000..f9d05b82d
--- /dev/null
+++ b/spine-ts/spine-construct3/src/type.ts
@@ -0,0 +1,13 @@
+
+const SDK = globalThis.SDK;
+
+const PLUGIN_CLASS = SDK.Plugins.EsotericSoftware_SpineConstruct3;
+
+PLUGIN_CLASS.Type = class MyDrawingPluginType extends SDK.ITypeBase {
+ constructor (sdkPlugin: SDK.IPluginBase, iObjectType: SDK.IObjectType) {
+ super(sdkPlugin, iObjectType);
+ }
+
+};
+
+export { }
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/8 Direction/I8DirectionBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/8 Direction/I8DirectionBehaviorInstance.d.ts
new file mode 100644
index 000000000..134e66496
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/8 Direction/I8DirectionBehaviorInstance.d.ts
@@ -0,0 +1,23 @@
+
+type SimulateControlType8Direction = "left" | "right" | "up" | "down";
+
+/** Represents the 8 Direction behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/direction | I8DirectionBehaviorInstance documentation } */
+declare class I8DirectionBehaviorInstance extends IBehaviorInstance
+{
+ stop(): void;
+ reverse(): void;
+ simulateControl(ctrl: SimulateControlType8Direction): void;
+ speed: number;
+ maxSpeed: number;
+ acceleration: number;
+ deceleration: number;
+ vectorX: number;
+ vectorY: number;
+ setVector(x: number, y: number): void;
+ getVector(): Vec2Arr;
+ isDefaultControls: boolean;
+ isIgnoringInput: boolean;
+ isAllowSliding: boolean;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Anchor/IAnchorBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Anchor/IAnchorBehaviorInstance.d.ts
new file mode 100644
index 000000000..8d0eef8cd
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Anchor/IAnchorBehaviorInstance.d.ts
@@ -0,0 +1,7 @@
+
+/** Represents the Anchor behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/anchor | IAnchorBehaviorInstance documentation } */
+declare class IAnchorBehaviorInstance extends IBehaviorInstance
+{
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Bullet/IBulletBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Bullet/IBulletBehaviorInstance.d.ts
new file mode 100644
index 000000000..7d134cd2a
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Bullet/IBulletBehaviorInstance.d.ts
@@ -0,0 +1,13 @@
+
+/** Represents the Bullet behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/bullet | IBulletBehaviorInstance documentation } */
+declare class IBulletBehaviorInstance extends IBehaviorInstance
+{
+ speed: number;
+ acceleration: number;
+ gravity: number;
+ angleOfMotion: number;
+ bounceOffSolids: boolean;
+ distanceTravelled: number;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Car/ICarBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Car/ICarBehaviorInstance.d.ts
new file mode 100644
index 000000000..abbce4d32
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Car/ICarBehaviorInstance.d.ts
@@ -0,0 +1,25 @@
+
+type SimulateControlTypeCar = "left" | "right" | "up" | "down";
+
+/** Represents the Car behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/car | ICarBehaviorInstance documentation } */
+declare class ICarBehaviorInstance extends IBehaviorInstance
+{
+ stop(): void;
+ simulateControl(ctrl: SimulateControlTypeCar): void;
+ speed: number;
+ maxSpeed: number;
+ acceleration: number;
+ deceleration: number;
+ readonly vectorX: number;
+ readonly vectorY: number;
+ getVector(): Vec2Arr;
+ readonly angleOfMotion: number;
+ steerSpeed: number;
+ driftRecover: number;
+ friction: number;
+ turnWhileStopped: boolean;
+ isDefaultControls: boolean;
+ isIgnoringInput: boolean;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Drag & Drop/IDragDropBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Drag & Drop/IDragDropBehaviorInstance.d.ts
new file mode 100644
index 000000000..577261bc6
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Drag & Drop/IDragDropBehaviorInstance.d.ts
@@ -0,0 +1,20 @@
+
+type DragDropBehaviorAxes = "both" | "horizontal" | "vertical";
+
+interface DragDropBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "dragstart": BehaviorInstanceEvent;
+ "drop": BehaviorInstanceEvent;
+}
+
+/** Represents the Car behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/drag-drop | IDragDropBehaviorInstance documentation } */
+declare class IDragDropBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: DragDropBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: DragDropBehaviorInstanceEventMap[K]) => any): void;
+
+ axes: DragDropBehaviorAxes;
+ drop(): void;
+ readonly isDragging: boolean;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Fade/IFadeBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Fade/IFadeBehaviorInstance.d.ts
new file mode 100644
index 000000000..75f7e6d9e
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Fade/IFadeBehaviorInstance.d.ts
@@ -0,0 +1,20 @@
+
+interface FadeBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "fadeinend": BehaviorInstanceEvent;
+ "waitend": BehaviorInstanceEvent;
+ "fadeoutend": BehaviorInstanceEvent;
+}
+
+/** Represents the Fade behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/fade | IFadeBehaviorInstance documentation } */
+declare class IFadeBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: FadeBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: FadeBehaviorInstanceEventMap[K]) => any): void;
+
+ startFade(): void;
+ restartFade(): void;
+ fadeInTime: number;
+ waitTime: number;
+ fadeOutTime: number;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Flash/IFlashBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Flash/IFlashBehaviorInstance.d.ts
new file mode 100644
index 000000000..dcaf37fbb
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Flash/IFlashBehaviorInstance.d.ts
@@ -0,0 +1,16 @@
+
+interface FlashBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "flashend": BehaviorInstanceEvent;
+}
+
+/** Represents the Flash behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/flash | IFlashBehaviorInstance documentation } */
+declare class IFlashBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: FlashBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: FlashBehaviorInstanceEventMap[K]) => any): void;
+
+ flash(on: number, off: number, dur: number): void;
+ stop(): void;
+ readonly isFlashing: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Follow/IFollowBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Follow/IFollowBehaviorInstance.d.ts
new file mode 100644
index 000000000..8df8043b5
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Follow/IFollowBehaviorInstance.d.ts
@@ -0,0 +1,32 @@
+
+type FollowBehaviorMode = "time" | "distance";
+type FollowBehaviorInterpolationType = "step" | "linear" | "angular";
+type FollowBehaviorPropertyType = "x" | "y" | "z-elevation" | "width" | "height" | "angle" | "opacity" | "visibility" | "destroyed";
+
+/** Represents the Follow behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/follow | IFollowBehaviorInstance documentation } */
+declare class IFollowBehaviorInstance extends IBehaviorInstance
+{
+ followInstance: IInstance;
+ mode: FollowBehaviorMode;
+ delay: number;
+ maxDelay: number;
+ historyRate: number;
+ clearHistory(): void;
+ rewindHistory(time: number): void;
+ setFollowingProperty(prop: FollowBehaviorPropertyType, isEnabled: boolean): void;
+ isFollowingProperty(prop: FollowBehaviorPropertyType): boolean;
+ setPropertyInterpolation(prop: FollowBehaviorPropertyType, interp: FollowBehaviorInterpolationType): void;
+ getPropertyInterpolation(prop: FollowBehaviorPropertyType): FollowBehaviorInterpolationType;
+
+ startFollowingCustomProperty(customProp: string, interp: FollowBehaviorInterpolationType): void;
+ stopFollowingCustomProperty(customProp: string): void;
+ isFollowingCustomProperty(customProp: string): boolean;
+ setCustomPropertyValue(customProp: string, value: number|string): void;
+ getDelayedCustomPropertyValue(customProp: string): number|string;
+
+ saveHistoryToJSON(maxDelay?: number): JSONValue;
+ loadHistoryFromJSON(json: JSONValue): void;
+
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Jump-thru/IJumpthruBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Jump-thru/IJumpthruBehaviorInstance.d.ts
new file mode 100644
index 000000000..1317d0e67
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Jump-thru/IJumpthruBehaviorInstance.d.ts
@@ -0,0 +1,7 @@
+
+/** Represents the Jump-thru behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/jump-thru | IJumpthruBehaviorInstance documentation } */
+declare class IJumpthruBehaviorInstance extends IBehaviorInstance
+{
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorInstance.d.ts
new file mode 100644
index 000000000..787574829
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorInstance.d.ts
@@ -0,0 +1,16 @@
+
+/** Represents the Line-of-sight behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/line-of-sight | ILOSBehaviorInstance documentation } */
+declare class ILOSBehaviorInstance extends IBehaviorInstance
+{
+ ray: ILOSBehaviorRay;
+
+ range: number;
+ coneOfView: number;
+ hasLOStoPosition(x: number, y: number): boolean;
+ hasLOSBetweenPositions(fromX: number, fromY: number, fromAngle: number, toX: number, toY: number): boolean;
+ castRay(fromX: number, fromY: number, toX: number, toY: number, useCollisionCells?: boolean): ILOSBehaviorRay;
+
+ addObstacle(objectClass: IObjectClass): void;
+ clearObstacles(): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorRay.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorRay.d.ts
new file mode 100644
index 000000000..7d23019a0
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Line of sight/ILOSBehaviorRay.d.ts
@@ -0,0 +1,20 @@
+
+/** Represents the result of casting a ray with the Line-of-sight behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/line-of-sight | ILOSBehaviorInstance documentation } */
+declare class ILOSBehaviorRay
+{
+ readonly didCollide: boolean;
+ readonly hitX: number;
+ readonly hitY: number;
+ getHitPosition(): Vec2Arr;
+ readonly hitDistance: number;
+ readonly hitUid: number;
+ getNormalX(length: number): number;
+ getNormalY(length: number): number;
+ getNormal(length: number): Vec2Arr;
+ readonly normalAngle: number;
+ getReflectionX(length: number): number;
+ getReflectionY(length: number): number;
+ getReflection(length: number): Vec2Arr;
+ readonly reflectionAngle: number;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Move To/IMoveToBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Move To/IMoveToBehaviorInstance.d.ts
new file mode 100644
index 000000000..286ece600
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Move To/IMoveToBehaviorInstance.d.ts
@@ -0,0 +1,32 @@
+
+interface MoveToBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "arrived": BehaviorInstanceEvent;
+ "hitsolid": BehaviorInstanceEvent;
+}
+
+/** Represents the Move To behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/move | IMoveToBehaviorInstance documentation } */
+declare class IMoveToBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: MoveToBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: MoveToBehaviorInstanceEventMap[K]) => any): void;
+
+ moveToPosition(x: number, y: number, isDirect?: boolean): void;
+ getTargetX(): number;
+ getTargetY(): number;
+ getTargetPosition(): Vec2Arr;
+ getWaypointCount(): number;
+ getWaypointX(index: number): number;
+ getWaypointY(index: number): number;
+ getWaypoint(index: number): number;
+ stop(): void;
+ readonly isMoving: boolean;
+ speed: number;
+ maxSpeed: number;
+ acceleration: number;
+ deceleration: number;
+ angleOfMotion: number;
+ rotateSpeed: number;
+ isStopOnSolids: boolean;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Orbit/IOrbitBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Orbit/IOrbitBehaviorInstance.d.ts
new file mode 100644
index 000000000..47fa15c2c
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Orbit/IOrbitBehaviorInstance.d.ts
@@ -0,0 +1,20 @@
+
+/** Represents the Orbit behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/orbit | IOrbitBehaviorInstance documentation } */
+declare class IOrbitBehaviorInstance extends IBehaviorInstance
+{
+ setTargetPosition(x: number, y: number): void;
+ getTargetPosition(): Vec2Arr;
+ pin(inst: IWorldInstance): void;
+ speed: number;
+ acceleration: number;
+ rotation: number;
+ offsetAngle: number;
+ primaryRadius: number;
+ secondaryRadius: number;
+ isMatchRotation: boolean;
+ totalRotation: number;
+ totalAbsoluteRotation: number;
+ getDistanceToTarget(): number;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingBehaviorInstance.d.ts
new file mode 100644
index 000000000..68fc24f55
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingBehaviorInstance.d.ts
@@ -0,0 +1,38 @@
+
+type PathfindingDirectMovementMode = "none" | "to-destination" | "anywhere-along-path";
+
+interface PathfindingBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "arrived": BehaviorInstanceEvent;
+}
+
+/** Represents the Pathfinding behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/pathfinding | IPathfindingBehaviorInstance documentation } */
+declare class IPathfindingBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: PathfindingBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: PathfindingBehaviorInstanceEventMap[K]) => any): void;
+
+ readonly map: IPathfindingMap;
+
+ findPath(x: number, y: number): Promise;
+ calculatePath(fromX: number, fromY: number, toX: number, toY: number): Promise;
+ startMoving(): void;
+ stop(): void;
+ maxSpeed: number;
+ speed: number;
+ acceleration: number;
+ deceleration: number;
+ rotateSpeed: number;
+ readonly isCalculatingPath: boolean;
+ readonly isMoving: boolean;
+ readonly currentNode: number;
+
+ getNodeCount(): number;
+ getNodeXAt(index: number): number;
+ getNodeYAt(index: number): number;
+ getNodeAt(index: number): Vec2Arr;
+ nodes(): Generator;
+
+ directMovementMode: PathfindingDirectMovementMode;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingMap.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingMap.d.ts
new file mode 100644
index 000000000..40d826a5d
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Pathfinding/IPathfindingMap.d.ts
@@ -0,0 +1,18 @@
+
+/** Represents a shared pathfinding obstacle map for the Pathfinding behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/pathfinding | IPathfindingBehaviorInstance documentation } */
+declare class IPathfindingMap
+{
+ readonly cellSize: number;
+ readonly cellBorder: number;
+ readonly widthInCells: number;
+ readonly heightInCells: number;
+ isCellObstacle(x: number, y: number): boolean;
+ moveCost: number;
+ isDiagonalsEnabled: boolean;
+ regenerateMap(): Promise;
+ regenerateRegion(startX: number, startY: number, endX: number, endY: number): Promise;
+ regenerateObjectRegion(objectClass: IObjectClass): Promise;
+ startPathGroup(baseCost?: number, cellSpread?: number, maxWorkers?: number): void;
+ endPathGroup(): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehavior.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehavior.d.ts
new file mode 100644
index 000000000..9aa9dd6f9
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehavior.d.ts
@@ -0,0 +1,13 @@
+
+type PhysicsSteppingMode = "fixed" | "variable";
+
+/** Represents global settings with the Physics behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/physics | IPhysicsBehaviorInstance documentation } */
+declare class IPhysicsBehavior extends IBehavior_
+{
+ worldGravity: number;
+ steppingMode: PhysicsSteppingMode;
+ velocityIterations: number;
+ positionIterations: number;
+ setCollisionsEnabled(objectClassA: IObjectClass, objectClassB: IObjectClass, state: boolean): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehaviorInstance.d.ts
new file mode 100644
index 000000000..7d53d3a82
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Physics/IPhysicsBehaviorInstance.d.ts
@@ -0,0 +1,59 @@
+
+/** Represents the Physics behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/physics | IPhysicsBehaviorInstance documentation } */
+declare class IPhysicsBehaviorInstance extends IBehaviorInstance
+{
+ readonly behavior: IPhysicsBehavior;
+
+ isEnabled: boolean;
+ angularVelocity: number;
+ density: number;
+ friction: number;
+ elasticity: number;
+ linearDamping: number;
+ angularDamping: number;
+ isImmovable: boolean;
+ isPreventRotation: boolean;
+ isBullet: boolean;
+ readonly mass: number;
+
+ /**
+ * @deprecated Use isAwake (which also has a setter) instead of isSleeping
+ */
+ readonly isSleeping: boolean;
+ isAwake: boolean;
+
+ applyForce(fx: number, fy: number, imgPt?: ImagePointParameter): void;
+ applyForceTowardPosition(f: number, px: number, py: number, imgPt?: ImagePointParameter): void;
+ applyForceAtAngle(f: number, a: number, imgPt?: ImagePointParameter): void;
+
+ applyImpulse(ix: number, iy: number, imgPt?: ImagePointParameter): void;
+ applyImpulseTowardPosition(i: number, px: number, py: number, imgPt?: ImagePointParameter): void;
+ applyImpulseAtAngle(i: number, a: number, imgPt?: ImagePointParameter): void;
+
+ applyTorque(m: number): void;
+ applyTorqueToAngle(m: number, a: number): void;
+ applyTorqueToPosition(m: number, px: number, py: number): void;
+
+ setVelocity(vx: number, vy: number): void;
+ getVelocityX(): number;
+ getVelocityY(): number;
+ getVelocity(): Vec2Arr;
+
+ teleport(x: number, y: number): void;
+
+ getCenterOfMassX(): number;
+ getCenterOfMassY(): number;
+ getCenterOfMass(): Vec2Arr;
+
+ getContactCount(): number;
+ getContactX(): number;
+ getContactY(): number;
+ getContact(): Vec2Arr;
+
+ createDistanceJoint(imgPt: ImagePointParameter, otherInst: IWorldInstance, otherImgPt: ImagePointParameter, damping: number, freq: number): void;
+ createRevoluteJoint(imgPt: ImagePointParameter, otherInst: IWorldInstance): void;
+ createLimitedRevoluteJoint(imgPt: ImagePointParameter, otherInst: IWorldInstance, lower: number, upper: number): void;
+ createPrismaticJoint(imgPt: ImagePointParameter, otherInst: IWorldInstance, axisAngle: number, enableLimit: boolean, lowerTranslation: number, upperTranslation: number, enableMotor: boolean, motorSpeed: number, maxMotorForce: number): void;
+ removeAllJoints(): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Platform/IPlatformBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Platform/IPlatformBehaviorInstance.d.ts
new file mode 100644
index 000000000..4a949c4dd
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Platform/IPlatformBehaviorInstance.d.ts
@@ -0,0 +1,36 @@
+
+type SimulateControlTypePlatform = "left" | "right" | "jump";
+type PlatformCeilingCollisionMode = "stop" | "preserve-momentum";
+type PlatformWallSide = "left" | "right";
+
+/** Represents the Platform behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/platform | IPlatformBehaviorInstance documentation } */
+declare class IPlatformBehaviorInstance extends IBehaviorInstance
+{
+ fallThrough(): void;
+ resetDoubleJump(d: boolean): void;
+ simulateControl(ctrl: SimulateControlTypePlatform): void;
+ speed: number;
+ maxSpeed: number;
+ acceleration: number;
+ deceleration: number;
+ jumpStrength: number;
+ maxFallSpeed: number;
+ gravity: number;
+ gravityAngle: number;
+ isDoubleJumpEnabled: boolean;
+ jumpSustain: number;
+ ceilingCollisionMode: PlatformCeilingCollisionMode;
+ isByWall(side: PlatformWallSide): boolean;
+ readonly isOnFloor: boolean;
+ readonly isMoving: boolean;
+ readonly isJumping: boolean;
+ readonly isFalling: boolean;
+ vectorX: number;
+ vectorY: number;
+ setVector(x: number, y: number): void;
+ getVector(): Vec2Arr;
+ isDefaultControls: boolean;
+ isIgnoringInput: boolean;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Rotate/IRotateBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Rotate/IRotateBehaviorInstance.d.ts
new file mode 100644
index 000000000..88f6e2432
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Rotate/IRotateBehaviorInstance.d.ts
@@ -0,0 +1,9 @@
+
+/** Represents the Rotate behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/rotate | IRotateBehaviorInstance documentation } */
+declare class IRotateBehaviorInstance extends IBehaviorInstance
+{
+ speed: number;
+ acceleration: number;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Shadow caster/IShadowCasterBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Shadow caster/IShadowCasterBehaviorInstance.d.ts
new file mode 100644
index 000000000..67d945a0f
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Shadow caster/IShadowCasterBehaviorInstance.d.ts
@@ -0,0 +1,9 @@
+
+/** Represents the Shadow Caster behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/shadow-caster | IShadowCasterBehaviorInstance documentation } */
+declare class IShadowCasterBehaviorInstance extends IBehaviorInstance
+{
+ height: number;
+ tag: string;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Sine/ISineBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Sine/ISineBehaviorInstance.d.ts
new file mode 100644
index 000000000..b0c04016b
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Sine/ISineBehaviorInstance.d.ts
@@ -0,0 +1,17 @@
+
+type SineBehaviorMovementType = "horizontal" | "vertical" | "size" | "width" | "height" | "angle" | "opacity" | "value-only" | "forwards-backwards" | "z-elevation";
+type SineBehaviorWaveType = "sine" | "triangle" | "sawtooth" | "reverse-sawtooth" | "square";
+
+/** Represents the Sine behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/sine | ISineBehaviorInstance documentation } */
+declare class ISineBehaviorInstance extends IBehaviorInstance
+{
+ period: number;
+ magnitude: number;
+ phase: number;
+ movement: SineBehaviorMovementType;
+ wave: SineBehaviorWaveType;
+ readonly value: number;
+ updateInitialState(): void;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Solid/ISolidBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Solid/ISolidBehaviorInstance.d.ts
new file mode 100644
index 000000000..b69cf92b9
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Solid/ISolidBehaviorInstance.d.ts
@@ -0,0 +1,8 @@
+
+/** Represents the Solid behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/solid | ISolidBehaviorInstance documentation } */
+declare class ISolidBehaviorInstance extends IBehaviorInstance
+{
+ tags: string;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Tile movement/ITileMovementBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Tile movement/ITileMovementBehaviorInstance.d.ts
new file mode 100644
index 000000000..076ef71a0
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Tile movement/ITileMovementBehaviorInstance.d.ts
@@ -0,0 +1,26 @@
+
+type SimulateControlTypeTile = "left" | "right" | "up" | "down";
+
+/** Represents the Tile Movement behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/tile-movement | ITileMovementBehaviorInstance documentation } */
+declare class ITileMovementBehaviorInstance extends IBehaviorInstance
+{
+ isIgnoringInput: boolean;
+ isEnabled: boolean;
+ isDefaultControls: boolean;
+ simulateControl(dir: SimulateControlTypeTile): void;
+
+ setSpeed(x: number, y: number): void;
+ getSpeed(): Vec2Arr;
+ setGridPosition(x: number, y: number, immediate?: boolean): void;
+ getGridPosition(): Vec2Arr;
+ modifyGridDimensions(width: number, height: number, x: number, y: number): void;
+ isMoving(): boolean;
+ isMovingDirection(dir: SimulateControlTypeTile): boolean;
+ canMoveTo(x: number, y: number): boolean;
+ canMoveDirection(dir: SimulateControlTypeTile, distance: number): boolean;
+ getTargetPosition(): Vec2Arr;
+ getGridTargetPosition(): Vec2Arr;
+ toGridSpace(x: number, y: number): Vec2Arr;
+ fromGridSpace(x: number, y: number): Vec2Arr;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Timer/ITimerBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Timer/ITimerBehaviorInstance.d.ts
new file mode 100644
index 000000000..01e2f11cb
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Timer/ITimerBehaviorInstance.d.ts
@@ -0,0 +1,31 @@
+
+type TimerBehaviorTimerType = "once" | "regular";
+
+declare class TimerBehaviorEvent> extends BehaviorInstanceEvent
+{
+ tag: string;
+}
+
+interface TimerBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "timer": TimerBehaviorEvent;
+}
+
+/** Represents the Timer behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/timer | ITimerBehaviorInstance documentation } */
+declare class ITimerBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: TimerBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: TimerBehaviorInstanceEventMap[K]) => any): void;
+
+ startTimer(duration: number, name: string, type?: TimerBehaviorTimerType): void;
+ setTimerPaused(name: string, isPaused: boolean): void;
+ setAllTimersPaused(isPaused: boolean): void;
+ stopTimer(name: string): void;
+ stopAllTimers(): void;
+ isTimerRunning(name: string): boolean;
+ isTimerPaused(name: string): boolean;
+ getCurrentTime(name: string): number;
+ getTotalTime(name: string): number;
+ getDuration(name: string): number;
+ hasFinished(name: string): boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Turret/ITurretBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Turret/ITurretBehaviorInstance.d.ts
new file mode 100644
index 000000000..1240d2075
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Turret/ITurretBehaviorInstance.d.ts
@@ -0,0 +1,30 @@
+
+type TurretBehaviorTargetMode = "first" | "nearest";
+
+declare class TurretBehaviorEvent> extends BehaviorInstanceEvent
+{
+ targetInst: IWorldInstance;
+}
+
+interface TurretBehaviorInstanceEventMap extends BehaviorInstanceEventMap {
+ "targetacquired": TurretBehaviorEvent;
+ "shoot": TurretBehaviorEvent;
+}
+
+/** Represents the Turret behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/turret | ITurretBehaviorInstance documentation } */
+declare class ITurretBehaviorInstance extends IBehaviorInstance
+{
+ addEventListener>(type: K, listener: (ev: TurretBehaviorInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: TurretBehaviorInstanceEventMap[K]) => any): void;
+
+ currentTarget: IWorldInstance | null;
+ range: number;
+ rateOfFire: number;
+ isRotateEnabled: boolean;
+ rotateSpeed: number;
+ targetMode: TurretBehaviorTargetMode;
+ isPredictiveAimEnabled: boolean;
+ projectileSpeed: number;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/behaviors/Tween/ITweenBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/behaviors/Tween/ITweenBehaviorInstance.d.ts
new file mode 100644
index 000000000..49731d54e
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/behaviors/Tween/ITweenBehaviorInstance.d.ts
@@ -0,0 +1,27 @@
+
+type TweenPropertyType = "x" | "y" | "width" | "height" | "angle" | "opacity" | "color" | "z-elevation" | "x-scale" | "y-scale" | "position" | "size" | "scale" | "value";
+type TweenEndValueType = number | Vec2Arr | Vec3Arr;
+type TweenBuiltInEaseType = "linear" | "in-sine" | "out-sine" | "in-out-sine" | "in-elastic" | "out-elastic" | "in-out-elastic" | "in-back" | "out-back" | "in-out-back" |
+ "in-bounce" | "out-bounce" | "in-out-bounce" | "in-cubic" | "out-cubic" | "in-out-cubic" | "in-quadratic" | "out-quadratic" | "in-out-quadratic" |
+ "in-quartic" | "out-quartic" | "in-out-quartic" | "in-quintic" | "out-quintic" | "in-out-quintic" | "in-circular" | "out-circular" | "in-out-circular" |
+ "in-exponential" | "out-exponential" | "in-out-exponential";
+
+interface StartTweenOpts {
+ tags?: string | string[];
+ destroyOnComplete?: boolean;
+ loop?: boolean;
+ pingPong?: boolean;
+ repeatCount?: number;
+ startValue?: number;
+}
+
+/** Represents the Tween behavior.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/behavior-interfaces/tween | ITweenBehaviorInstance documentation } */
+declare class ITweenBehaviorInstance extends IBehaviorInstance
+{
+ startTween(prop: TweenPropertyType, endValue: TweenEndValueType, time: number, ease: TweenBuiltInEaseType, opts?: StartTweenOpts): ITweenState;
+
+ allTweens(): Generator;
+ tweensByTags(tags: string | string[]): Generator;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IBehaviorBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorBase.d.ts
new file mode 100644
index 000000000..556eb7fca
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorBase.d.ts
@@ -0,0 +1,12 @@
+declare namespace SDK {
+ class IBehaviorBase {
+
+ constructor(id: string);
+
+ _info: SDK.IBehaviorInfo;
+
+ Release(): void;
+
+ static Register(id: string, class_: new () => SDK.IBehaviorBase): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInfo.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInfo.d.ts
new file mode 100644
index 000000000..0dfd14b16
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInfo.d.ts
@@ -0,0 +1,30 @@
+
+type BehaviorInfoCategory = "attributes" | "general" | "movements" | "other";
+
+declare namespace SDK {
+ class IBehaviorInfo {
+ SetName(v: string): void;
+ SetDescription(v: string): void;
+ SetVersion(v: string): void;
+ SetCategory(v: BehaviorInfoCategory): void;
+ SetAuthor(v: string): void;
+ SetHelpUrl(v: string): void;
+ SetIcon(url: string, type: string): void;
+
+ SetIsOnlyOneAllowed(o: boolean): void;
+ SetIsDeprecated(d: boolean): void;
+ SetCanBeBundled(b: boolean): void;
+
+ SetProperties(arr: SDK.PluginProperty[]): void;
+
+ AddCordovaPluginReference(o: PluginInfoCordovaPluginReference): void;
+ AddFileDependency(o: PluginInfoFileDependency): void;
+ AddRemoteScriptDependency(url: string, type?: PluginInfoScriptType): void;
+
+ SetRuntimeModuleMainScript(path: string): void;
+ AddC3RuntimeScript(path: string): void;
+ SetC3RuntimeScripts(arr: string[]): void;
+ SetTypeScriptDefinitionFiles(arr: string[]): void;
+ SetScriptInterfaceNames(o: { instance?: string, behaviorType?: string, behavior?: string }): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInstanceBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInstanceBase.d.ts
new file mode 100644
index 000000000..376ff2569
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorInstanceBase.d.ts
@@ -0,0 +1,17 @@
+declare namespace SDK {
+ class IBehaviorInstanceBase {
+
+ constructor(sdkBehaviorType: SDK.IBehaviorTypeBase, iBehaviorInstance: SDK.IBehaviorInstance);
+
+ _sdkBehaviorType: SDK.IBehaviorTypeBase;
+ _behaviorInstance: SDK.IBehaviorInstance;
+
+ GetBehaviorInstance(): SDK.IBehaviorInstance;
+ GetSdkBehaviorType(): SDK.IBehaviorTypeBase;
+
+ Release(): void;
+ OnCreate(): void;
+
+ OnPropertyChanged(id: string, value: EditorPropertyValueType): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IBehaviorTypeBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorTypeBase.d.ts
new file mode 100644
index 000000000..8670d9814
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IBehaviorTypeBase.d.ts
@@ -0,0 +1,8 @@
+declare namespace SDK {
+ class IBehaviorTypeBase {
+ constructor(sdkBehavior: SDK.IBehaviorBase, iBehaviorType: SDK.IBehaviorType);
+
+ _sdkBehavior: SDK.IBehaviorBase;
+ _behaviorType: SDK.IBehaviorType;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IInstanceBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IInstanceBase.d.ts
new file mode 100644
index 000000000..135647c58
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IInstanceBase.d.ts
@@ -0,0 +1,21 @@
+declare namespace SDK {
+ class IInstanceBase {
+
+ constructor(sdkType: SDK.ITypeBase, iInstance: SDK.IObjectInstance);
+
+ _sdkType: SDK.ITypeBase;
+ _inst: SDK.IObjectInstance;
+
+ Release(): void;
+ OnCreate(): void;
+ OnAfterCreate(): void;
+ OnPropertyChanged(id: string, value: EditorPropertyValueType): void;
+ OnTimelinePropertyChanged(id: string, value: number | string, detail: { resultMode: "relative" | "absolute" }): void;
+ OnExitTimelineEditMode(): void;
+
+ LoadC2Property(name: string, valueString: string): boolean;
+ GetObjectType(): SDK.IObjectType;
+ GetProject(): SDK.IProject;
+ GetInstance(): SDK.IObjectInstance;
+ }
+}
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IPluginBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IPluginBase.d.ts
new file mode 100644
index 000000000..173af0e7b
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IPluginBase.d.ts
@@ -0,0 +1,14 @@
+
+
+declare namespace SDK {
+ class IPluginBase {
+
+ constructor(id: string);
+
+ _info: SDK.IPluginInfo;
+
+ Release(): void;
+
+ static Register(id: string, class_: new () => SDK.IPluginBase): void;
+ }
+}
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IPluginInfo.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IPluginInfo.d.ts
new file mode 100644
index 000000000..a1d4f62d7
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IPluginInfo.d.ts
@@ -0,0 +1,80 @@
+
+type PluginInfoCategory = "3d" | "data-and-storage" | "html-elements" | "general" | "input" | "media" | "monetisation" | "platform-specific" | "web" | "other";
+type PluginInfoPluginType = "object" | "world";
+type PluginInfoScriptType = "" | "module";
+
+interface PluginInfoCordovaPluginReference {
+ id: string,
+ version?: string,
+ platform?: "all" | "ios" | "android",
+ plugin?: SDK.IPluginBase,
+ variables?: Array<[string, SDK.PluginProperty]>
+}
+
+interface PluginInfoCordovaResourceFile {
+ src: string,
+ target?: string,
+ platform?: "all" | "ios" | "android"
+}
+
+interface PluginInfoFileDependency {
+ filename: string,
+ fileType?: string,
+ scriptType?: PluginInfoScriptType,
+ type: "copy-to-output" | "external-dom-script" | "external-runtime-script" | "external-css" | "wrapper-extension",
+ platform?: "all" | "windows-x86" | "windows-x64" | "windows-arm64" | "xbox-uwp-x64" | "macos-universal" | "linux-x64" | "linux-arm" | "linux-arm64"
+}
+
+declare namespace SDK {
+ class IPluginInfo {
+ SetName(v: string): void;
+ SetDescription(v: string): void;
+ SetVersion(v: string): void;
+ SetCategory(v: PluginInfoCategory): void;
+ SetAuthor(v: string): void;
+ SetHelpUrl(v: string): void;
+ SetPluginType(v: PluginInfoPluginType): void;
+ SetIcon(url: string, type: string): void;
+
+ SetIsResizable(v: boolean): void;
+ SetIsRotatable(v: boolean): void;
+ SetSupportsZElevation(v: boolean): void;
+ SetHasImage(v: boolean): void;
+ SetDefaultImageURL(v: string): void;
+ SetHasAnimations(v: boolean): void;
+ SetIsTiled(v: boolean): void;
+ SetIsFont(v: boolean): void;
+ SetHasTilemap(v: boolean): void;
+ SetIsDeprecated(v: boolean): void;
+ SetIsSingleGlobal(v: boolean): void;
+ SetSupportsEffects(v: boolean): void;
+ SetMustPreDraw(v: boolean): void;
+ SetIs3D(v: boolean): void;
+ SetSupportsColor(v: boolean): void;
+ SetCanBeBundled(v: boolean): void;
+ SetSupportsColor(v: boolean): void;
+
+ AddCommonPositionACEs(): void;
+ AddCommonSizeACEs(): void;
+ AddCommonAngleACEs(): void;
+ AddCommonAppearanceACEs(): void;
+ AddCommonZOrderACEs(): void;
+ AddCommonSceneGraphACEs(): void;
+
+ SetProperties(arr: SDK.PluginProperty[]): void;
+
+ AddCordovaPluginReference(o: PluginInfoCordovaPluginReference): void;
+ AddCordovaResourceFile(o: PluginInfoCordovaResourceFile): void;
+ AddFileDependency(o: PluginInfoFileDependency): void;
+ AddRemoteScriptDependency(url: string, type?: PluginInfoScriptType): void;
+ SetGooglePlayServicesEnabled(e: boolean): void;
+ SetWrapperExportProperties(componentId: string, propertyIds: string[]): void;
+
+ SetRuntimeModuleMainScript(path: string): void;
+ AddC3RuntimeScript(path: string): void;
+ SetC3RuntimeScripts(arr: string[]): void;
+ SetDOMSideScripts(arr: string[]): void;
+ SetTypeScriptDefinitionFiles(arr: string[]): void;
+ SetScriptInterfaceNames(o: { instance?: string, objectType?: string, plugin?: string }): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IPluginProperty.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IPluginProperty.d.ts
new file mode 100644
index 000000000..e7ecffea3
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IPluginProperty.d.ts
@@ -0,0 +1,26 @@
+
+type PluginPropertyInitialValueType = number | Vec3Arr | string | boolean;
+
+type PluginPropertyType = "integer" | "float" | "percent" | "text" | "longtext" | "check" | "font" | "combo" | "color" | "object" | "group" | "link" | "info" | "projectfile";
+
+type PluginPropertyCallbackType = "for-each-instance" | "once-for-type";
+
+interface PluginPropertyOptions {
+ initialValue?: PluginPropertyInitialValueType,
+ minValue?: number,
+ maxValue?: number,
+ items?: string[],
+ dragSpeedMultiplier?: number,
+ allowedPluginIds?: string[],
+ linkCallback?: (p: SDK.IWorldInstanceBase | SDK.ITypeBase) => void,
+ infoCallback?: (inst: SDK.IInstanceBase) => string,
+ callbackType?: PluginPropertyCallbackType,
+ interpolatable?: boolean,
+ filter?: string
+}
+
+declare namespace SDK {
+ class PluginProperty {
+ constructor(type: PluginPropertyType, id: string, initialValue_or_options?: PluginPropertyOptions | PluginPropertyInitialValueType);
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/ITypeBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/ITypeBase.d.ts
new file mode 100644
index 000000000..9f7ddd596
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/ITypeBase.d.ts
@@ -0,0 +1,12 @@
+
+declare namespace SDK {
+ class ITypeBase {
+
+ constructor(sdkPlugin: SDK.IPluginBase, iObjectType: SDK.IObjectType);
+
+ _sdkPlugin: SDK.IPluginBase;
+ _objectType: SDK.IObjectType;
+
+ GetObjectType(): SDK.IObjectType;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/IWorldInstanceBase.d.ts b/spine-ts/spine-construct3/ts-defs/editor/IWorldInstanceBase.d.ts
new file mode 100644
index 000000000..5772faf00
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/IWorldInstanceBase.d.ts
@@ -0,0 +1,23 @@
+
+declare namespace SDK {
+ class IWorldInstanceBase extends SDK.IInstanceBase {
+
+ constructor(sdkType: SDK.ITypeBase, iInstance: SDK.IWorldInstance);
+
+ _inst: SDK.IWorldInstance;
+
+ Draw(iRenderer: SDK.Gfx.IWebGLRenderer, iDrawParams: SDK.Gfx.IDrawParams): void;
+ OnPlacedInLayout(): void;
+
+ GetTexture(animationFrame: SDK.IAnimationFrame): SDK.Gfx.IWebGLTexture | null;
+ GetTexRect(): SDK.Rect;
+ HadTextureError(): boolean;
+
+ IsOriginalSizeKnown(): boolean;
+ GetOriginalWidth(): number;
+ GetOriginalHeight(): number;
+
+ HasDoubleTapHandler(): boolean;
+ OnDoubleTap(): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/gfx/IDrawParams.d.ts b/spine-ts/spine-construct3/ts-defs/editor/gfx/IDrawParams.d.ts
new file mode 100644
index 000000000..f9421ffad
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/gfx/IDrawParams.d.ts
@@ -0,0 +1,6 @@
+declare namespace SDK.Gfx {
+ class IDrawParams {
+ GetDt(): number;
+ GetLayoutView(): SDK.UI.ILayoutView;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLRenderer.d.ts b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLRenderer.d.ts
new file mode 100644
index 000000000..2c52452f7
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLRenderer.d.ts
@@ -0,0 +1,53 @@
+// Note types like TextureCreateOptions are taken from the runtime type
+// definitions as they match the same types used by the editor
+
+declare namespace SDK.Gfx {
+ class IWebGLRenderer {
+ SetAlphaBlend(): void;
+
+ SetColorFillMode(): void;
+ SetTextureFillMode(): void;
+ SetSmoothLineFillMode(): void;
+
+ SetColor(color: SDK.Color): void;
+ SetColorRgba(r: number, g: number, b: number, a: number): void;
+ SetOpacity(opacity: number): void;
+ ResetColor(): void;
+
+ SetCurrentZ(z: number): void;
+ GetCurrentZ(): number;
+
+ Rect(r: SDK.Rect): void;
+ Rect2(left: number, top: number, right: number, bottom: number): void;
+
+
+ Quad(q: SDK.Quad): void;
+ Quad2(tlx: number, tly: number, trx: number, try_: number, brx: number, bry: number, blx: number, bly: number): void;
+ Quad3(q: SDK.Quad, r: SDK.Rect): void;
+ Quad4(q: SDK.Quad, uv: SDK.Quad): void;
+ Quad3D(tlx: number, tly: number, tlz: number, trx: number, try_: number, trz: number, brx: number, bry: number, brz: number, blx: number, bly: number, blz: number, r: SDK.Rect): void;
+ Quad3D2(tlx: number, tly: number, tlz: number, trx: number, try_: number, trz: number, brx: number, bry: number, brz: number, blx: number, bly: number, blz: number, uv: SDK.Quad): void;
+
+ DrawMesh(posArr: Float32Array, uvArr: Float32Array, indexArr: Uint16Array): void;
+
+ ConvexPoly(pts: number[]): void;
+ Line(x1: number, y1: number, x2: number, y2: number): void;
+ TexturedLine(x1: number, y1: number, x2: number, y2: number, u: number, v: number): void;
+
+ LineRect(left: number, top: number, right: number, bottom: number): void;
+ LineRect2(r: SDK.Rect): void;
+ LineQuad(q: SDK.Quad): void;
+
+ PushLineWidth(w: number): void;
+ PopLineWidth(): void;
+ PushLineCap(type: RendererLineCapMode): void;
+ PopLineCap(): void;
+
+ SetTexture(tex: SDK.Gfx.IWebGLTexture): void;
+ CreateDynamicTexture(width: number, height: number, opts?: TextureCreateOptions): SDK.Gfx.IWebGLTexture;
+ UpdateTexture(data: TextureUpdateDataType, tex: SDK.Gfx.IWebGLTexture, opts?: TextureUpdateOptions): void;
+ DeleteTexture(tex: SDK.Gfx.IWebGLTexture): void;
+
+ CreateRendererText(): SDK.Gfx.IWebGLText;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLText.d.ts b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLText.d.ts
new file mode 100644
index 000000000..c9cd0b1f1
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLText.d.ts
@@ -0,0 +1,30 @@
+// Note types like TextAlignHorizontalMode are taken from the runtime type
+// definitions as they match the same types used by the editor
+
+declare namespace SDK.Gfx {
+ class IWebGLText {
+ Release(): void;
+
+ SetFontName(fontName: string): void;
+ SetFontSize(fontSize: number): void;
+ SetLineHeight(h: number): void;
+ SetBold(b: boolean): void;
+ SetItalic(i: boolean): void;
+ SetColor(color: SDK.Color): void;
+ SetColorRgb(r: number, g: number, b: number): void;
+ SetHorizontalAlignment(h: TextAlignHorizontalMode): void;
+ SetVerticalAlignment(v: TextAlignVerticalMode): void;
+ SetWordWrapMode(mode: TextWordWrapMode): void;
+
+ SetText(text: string): void;
+ SetSize(width: number, height: number, zoomScale: number): void;
+
+ GetTexture(): SDK.Gfx.IWebGLTexture | null;
+ GetTexRect(): SDK.Rect;
+ SetTextureUpdateCallback(callback: () => void): void;
+ ReleaseTexture(): void;
+
+ GetTextWidth(): number;
+ GetTextHeight(): number;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLTexture.d.ts b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLTexture.d.ts
new file mode 100644
index 000000000..368522a9d
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/gfx/IWebGLTexture.d.ts
@@ -0,0 +1,6 @@
+declare namespace SDK.Gfx {
+ class IWebGLTexture {
+ GetWidth(): number;
+ GetHeight(): number;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/IColor.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/IColor.d.ts
new file mode 100644
index 000000000..889ab89b2
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/IColor.d.ts
@@ -0,0 +1,29 @@
+declare namespace SDK {
+ class Color {
+ constructor(r?: number, g?: number, b?: number, a?: number);
+
+ setRgb(r: number, g: number, b: number): void;
+ setRgba(r: number, g: number, b: number, a: number): void;
+
+ copy(c: SDK.Color): void;
+ copyRgb(c: SDK.Color): void;
+ clone(): SDK.Color;
+
+ setR(r: number): void;
+ getR(): number;
+ setG(g: number): void;
+ getG(): number;
+ setB(b: number): void;
+ getB(): number;
+ setA(a: number): void;
+ getA(): number;
+
+ equals(c: SDK.Color): boolean;
+ equalsIgnoringAlpha(c: SDK.Color): boolean;
+ equalsRgb(r: number, b: number, g: number): boolean;
+ equalsRgba(r: number, b: number, g: number, a: number): boolean;
+
+ premultiply(): void;
+ unpremultiply(): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/ILang.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/ILang.d.ts
new file mode 100644
index 000000000..d5262d2cc
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/ILang.d.ts
@@ -0,0 +1,9 @@
+
+declare namespace SDK.Lang {
+ function PushContext(str: string): void;
+ function PopContext(): void;
+ function Get(s: string): string;
+}
+
+// Global lang() method
+declare function lang(s: string): string;
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/IQuad.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/IQuad.d.ts
new file mode 100644
index 000000000..8803c3927
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/IQuad.d.ts
@@ -0,0 +1,40 @@
+declare namespace SDK {
+ class Quad {
+ constructor(tlx?: number, tly?: number, trx?: number, try_?: number, brx?: number, bry?: number, blx?: number, bly?: number);
+
+ set(tlx: number, tly: number, trx: number, try_: number, brx: number, bry: number, blx: number, bly: number): void;
+ setRect(left: number, top: number, right: number, bottom: number): void;
+
+ copy(q: SDK.Quad): void;
+
+ setTlx(v: number): void;
+ getTlx(): number;
+ setTly(v: number): void;
+ getTly(): number;
+ setTrx(v: number): void;
+ getTrx(): number;
+ setTry(v: number): void;
+ getTry(): number;
+ setBrx(v: number): void;
+ getBrx(): number;
+ setBry(v: number): void;
+ getBry(): number;
+ setBlx(v: number): void;
+ getBlx(): number;
+ setBly(v: number): void;
+ getBly(): number;
+
+ midX(): number;
+ midY(): number;
+
+ offset(x: number, y: number): void;
+
+ setFromRect(r: SDK.Rect): void;
+ setFromRotatedRect(r: SDK.Rect, a: number): void;
+ getBoundingBox(r: SDK.Rect): void;
+
+ containsPoint(x: number, y: number): boolean;
+ intersectsSegment(x1: number, y1: number, x2: number, y2: number): boolean;
+ intersectsQuad(q: SDK.Quad): boolean;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/IRect.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/IRect.d.ts
new file mode 100644
index 000000000..ae5d4af8b
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/IRect.d.ts
@@ -0,0 +1,33 @@
+declare namespace SDK {
+ class Rect {
+ constructor(left?: number, top?: number, right?: number, bottom?: number);
+
+ set(left: number, top: number, right: number, bottom: number): void;
+ copy(r: SDK.Rect): void;
+ clone(): SDK.Rect;
+
+ setLeft(left: number): void;
+ getLeft(): number;
+ setTop(top: number): void;
+ getTop(): number;
+ setRight(right: number): void;
+ getRight(): number;
+ setBottom(bottom: number): void;
+ getBottom(): number;
+
+ width(): number;
+ height(): number;
+ midX(): number;
+ midY(): number;
+
+ offset(x: number, y: number): void;
+ inflate(x: number, y: number): void;
+ deflate(x: number, y: number): void;
+ multiply(x: number, y: number): void;
+ divide(x: number, y: number): void;
+ clamp(left: number, top: number, right: number, bottom: number): void;
+ normalize(): void;
+ intersectsRect(r: SDK.Rect): boolean;
+ containsPoint(x: number, y: number): boolean;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFile.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFile.d.ts
new file mode 100644
index 000000000..8c7278f3e
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFile.d.ts
@@ -0,0 +1,12 @@
+declare namespace SDK {
+ class IZipFile {
+ PathExists(path: string): boolean;
+ GetFileList(): string[];
+ GetFirstEntryWithExtension(ext: string): SDK.IZipFileEntry | null;
+ GetEntry(path: string): SDK.IZipFileEntry | null;
+
+ ReadText(entry: SDK.IZipFileEntry): Promise;
+ ReadJson(entry: SDK.IZipFileEntry): Promise;
+ ReadBlob(entry: SDK.IZipFileEntry): Promise;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFileEntry.d.ts b/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFileEntry.d.ts
new file mode 100644
index 000000000..89d4a7fa3
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/misc/IZipFileEntry.d.ts
@@ -0,0 +1,5 @@
+declare namespace SDK {
+ class IZipFileEntry {
+
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/ILayer.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/ILayer.d.ts
new file mode 100644
index 000000000..1da5b9f89
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/ILayer.d.ts
@@ -0,0 +1,6 @@
+declare namespace SDK {
+ class ILayer {
+ GetName(): string;
+ GetLayout: SDK.ILayout;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/ILayout.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/ILayout.d.ts
new file mode 100644
index 000000000..bc93256c4
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/ILayout.d.ts
@@ -0,0 +1,8 @@
+declare namespace SDK {
+ class ILayout {
+ GetName(): string;
+ GetProject(): SDK.IProject;
+ GetEventSheet(): SDK.IEventSheet;
+ GetAllLayers(): SDK.ILayer[];
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/IProject.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/IProject.d.ts
new file mode 100644
index 000000000..4fb508b48
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/IProject.d.ts
@@ -0,0 +1,26 @@
+type EditorProjectFileKind = "general" | "sound" | "music" | "video" | "font" | "icon";
+
+declare namespace SDK {
+ class IProject {
+ GetName(): string;
+
+ GetSystemType(): SDK.IObjectType;
+ GetSingleGlobalObjectType(pluginId: string): SDK.IObjectType | null;
+ CreateObjectType(pluginId: string, name: string): Promise;
+ CreateFamily(name: string, members: SDK.IObjectType[]): SDK.IFamily;
+ GetObjectTypeByName(name: string): SDK.IObjectType | null;
+ GetFamilyByName(name: string): SDK.IFamily | null;
+ GetObjectClassByName(name: string): SDK.IObjectClass | null;
+ GetObjectClassBySID(sid: number): SDK.IObjectClass | null;
+ GetInstanceByUID(uid: number): SDK.IObjectInstance | null;
+
+ AddOrReplaceProjectFile(blob: Blob, filename: string, kind?: EditorProjectFileKind): void;
+ GetProjectFileByName(name: string): SDK.IProjectFile | null;
+ GetProjectFileByExportPath(path: string): SDK.IProjectFile | null;
+
+ ShowImportAudioDialog(fileList: Blob[]): void;
+ EnsureFontLoaded(fontName: string): Promise;
+
+ UndoPointChangeObjectInstancesProperty(instances: SDK.IObjectInstance | SDK.IObjectInstance[], propertyId: string): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/IProjectFile.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/IProjectFile.d.ts
new file mode 100644
index 000000000..d3e640560
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/IProjectFile.d.ts
@@ -0,0 +1,7 @@
+declare namespace SDK {
+ class IProjectFile {
+ GetName(): string;
+ GetProject(): SDK.IProjectFile;
+ GetBlob(): Blob;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventBlock.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventBlock.d.ts
new file mode 100644
index 000000000..121592a82
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventBlock.d.ts
@@ -0,0 +1,8 @@
+type EditorACParameterType = number | string | SDK.IObjectClass;
+
+declare namespace SDK {
+ class IEventBlock extends IEventParentRow {
+ AddCondition(iObjectClass: SDK.IObjectClass, iBehaviorType: null, cndId: string, params?: EditorACParameterType[]): void;
+ AddAction(iObjectClass: SDK.IObjectClass, iBehaviorType: null, actId: string, params?: EditorACParameterType[]): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventParentRow.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventParentRow.d.ts
new file mode 100644
index 000000000..2738f9369
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventParentRow.d.ts
@@ -0,0 +1,5 @@
+declare namespace SDK {
+ class IEventParentRow {
+ AddEventBlock(): Promise;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventSheet.d.ts b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventSheet.d.ts
new file mode 100644
index 000000000..1570da624
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/model/events/IEventSheet.d.ts
@@ -0,0 +1,7 @@
+declare namespace SDK {
+ class IEventSheet {
+ GetName(): string;
+ GetProject(): SDK.IProject;
+ GetRoot(): SDK.IEventParentRow;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimation.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimation.d.ts
new file mode 100644
index 000000000..918daf076
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimation.d.ts
@@ -0,0 +1,22 @@
+declare namespace SDK {
+ class IAnimation {
+ GetName(): string;
+ GetObjectType(): SDK.IObjectType;
+ GetFrames(): SDK.IAnimationFrame[];
+
+ AddFrame(blob: Blob, width: number, height: number): Promise;
+
+ SetSpeed(s: number): void;
+ GetSpeed(): number;
+ SetLooping(l: boolean): void;
+ IsLooping(): boolean;
+ SetPingPong(p: boolean): void;
+ IsPingPong(): boolean;
+ SetRepeatCount(r: number): void;
+ GetRepeatCount(): number;
+ SetRepeatTo(f: number): void;
+ GetRepeatTo(): number;
+
+ Delete(): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimationFrame.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimationFrame.d.ts
new file mode 100644
index 000000000..2e9a12d22
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IAnimationFrame.d.ts
@@ -0,0 +1,26 @@
+declare namespace SDK {
+ class IAnimationFrame {
+ GetObjectType(): SDK.IObjectType;
+ GetWidth(): number;
+ GetHeight(): number;
+ GetCachedWebGLTexture(): SDK.Gfx.IWebGLTexture | null;
+ GetTexRect(): SDK.Rect;
+
+ LoadWebGLTexture(): Promise;
+ GetBlob(): Blob;
+ ReplaceBlobAndDecode(blob: Blob): Promise;
+
+ SetDuration(d: number): void;
+ GetDuration(): number;
+ SetOriginX(x: number): void;
+ GetOriginX(): number;
+ SetOriginY(y: number): void;
+ GetOriginY(): number;
+
+ AddImagePoint(name: string, x: number, y: number): SDK.IImagePoint;
+ GetImagePoints(): SDK.IImagePoint[];
+ GetCollisionPoly(): SDK.ICollisionPoly;
+
+ Delete(): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorInstance.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorInstance.d.ts
new file mode 100644
index 000000000..c6c5c5c4d
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorInstance.d.ts
@@ -0,0 +1,12 @@
+declare namespace SDK {
+ class IBehaviorInstance {
+ GetProject(): SDK.IProject;
+
+ GetPropertyValue(id: string): EditorPropertyValueType;
+ SetPropertyValue(id: string, value: EditorPropertyValueType): void;
+
+ GetObjectInstance(): SDK.IObjectInstance;
+
+ GetExternalSdkInstance(): SDK.IBehaviorInstanceBase | null;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorType.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorType.d.ts
new file mode 100644
index 000000000..196488271
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IBehaviorType.d.ts
@@ -0,0 +1,6 @@
+declare namespace SDK {
+ class IBehaviorType {
+ GetProject(): SDK.IProject;
+ GetName(): string;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/ICollisionPoly.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/ICollisionPoly.d.ts
new file mode 100644
index 000000000..6582c1e96
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/ICollisionPoly.d.ts
@@ -0,0 +1,9 @@
+declare namespace SDK {
+ class ICollisionPoly {
+ Reset(): void;
+ IsDefault(): boolean;
+
+ GetPoints(): number[];
+ SetPoints(arr: number[]): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IContainer.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IContainer.d.ts
new file mode 100644
index 000000000..e58c20a90
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IContainer.d.ts
@@ -0,0 +1,14 @@
+
+type EditorContainerSelectMode = "normal" | "all" | "wrap";
+
+declare namespace SDK {
+ class IContainer {
+ IsActive(): boolean;
+
+ GetMembers(): SDK.IObjectType[];
+ RemoveObjectType(iObjectType: SDK.IObjectType): void;
+
+ SetSelectMode(mode: EditorContainerSelectMode): void;
+ GetSelectMode(): EditorContainerSelectMode;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IFamily.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IFamily.d.ts
new file mode 100644
index 000000000..8e23e8ae9
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IFamily.d.ts
@@ -0,0 +1,6 @@
+declare namespace SDK {
+ class IFamily extends IObjectClass {
+ GetMembers(): SDK.IObjectType[];
+ SetMembers(memberS: SDK.IObjectType[]): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IImagePoint.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IImagePoint.d.ts
new file mode 100644
index 000000000..eb3c12a5b
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IImagePoint.d.ts
@@ -0,0 +1,11 @@
+declare namespace SDK {
+ class IImagePoint {
+ GetAnimationFrame(): SDK.IAnimationFrame;
+ GetName(): string;
+ SetName(name: string): void;
+ SetX(x: number): void;
+ GetX(): number;
+ SetY(y: number): void;
+ GetY(): number;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectClass.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectClass.d.ts
new file mode 100644
index 000000000..f3ec0a2f8
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectClass.d.ts
@@ -0,0 +1,7 @@
+declare namespace SDK {
+ class IObjectClass {
+ GetProject(): SDK.IProject;
+ GetName(): string;
+ Delete(): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectInstance.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectInstance.d.ts
new file mode 100644
index 000000000..4c1aa13e3
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectInstance.d.ts
@@ -0,0 +1,15 @@
+declare namespace SDK {
+ class IObjectInstance {
+ GetProject(): SDK.IProject;
+ GetObjectType(): SDK.IObjectType;
+
+ GetUID(): number;
+
+ SetPropertyValue(id: string, value: EditorPropertyValueType): void;
+ GetPropertyValue(id: string): EditorPropertyValueType;
+
+ GetTimelinePropertyValue(id: string): EditorPropertyValueType;
+
+ GetExternalSdkInstance(): SDK.IInstanceBase | null;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectType.d.ts
new file mode 100644
index 000000000..c39bcbbd3
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IObjectType.d.ts
@@ -0,0 +1,18 @@
+declare namespace SDK {
+ class IObjectType extends IObjectClass {
+ GetImage(): SDK.IAnimationFrame;
+ EditImage(): void;
+
+ GetAnimations(): SDK.IAnimation[];
+ EditAnimations(): void;
+
+ AddAnimation(animName: string, frameBlob: Blob, frameWidth: number, frameHeight: number): Promise;
+
+ CreateWorldInstance(layer: SDK.ILayer): SDK.IWorldInstance;
+ GetAllInstances(): SDK.IWorldInstance[];
+
+ IsInContainer(): boolean;
+ GetContainer(): SDK.IContainer | null;
+ CreateContainer(initialObjectTypes: SDK.IObjectType[]): SDK.IContainer;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/objects/IWorldInstance.d.ts b/spine-ts/spine-construct3/ts-defs/editor/objects/IWorldInstance.d.ts
new file mode 100644
index 000000000..538af51c1
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/objects/IWorldInstance.d.ts
@@ -0,0 +1,40 @@
+declare namespace SDK {
+ class IWorldInstance extends IObjectInstance {
+ GetBoundingBox(): SDK.Rect;
+ GetQuad(): SDK.Quad;
+ GetColor(): SDK.Color;
+
+ SetOpacity(o: number): void;
+ GetOpacity(): number;
+
+ SetX(x: number): void;
+ GetX(): number;
+ SetY(y: number): void;
+ GetY(): number;
+ SetXY(x: number, y: number): void;
+
+ SetZElevation(z: number): void;
+ GetZElevation(): number;
+ GetTotalZElevation(): number;
+
+ SetWidth(w: number): void;
+ GetWidth(): number;
+ SetHeight(h: number): void;
+ GetHeight(): number;
+ SetSize(w: number, h: number): void;
+
+ SetOriginX(x: number): void;
+ GetOriginX(): number;
+ SetOriginY(y: number): void;
+ GetOriginY(): number;
+ SetOrigin(x: number, y: number): void;
+
+ SetAngle(a: number): void;
+ GetAngle(): number;
+
+ GetLayer(): SDK.ILayer;
+ GetLayout(): SDK.ILayout;
+
+ ApplyBlendMode(iRenderer: SDK.Gfx.IWebGLRenderer): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/sdk.d.ts b/spine-ts/spine-construct3/ts-defs/editor/sdk.d.ts
new file mode 100644
index 000000000..09e7cef38
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/sdk.d.ts
@@ -0,0 +1,11 @@
+
+declare namespace SDK {
+ let Plugins: any;
+ let Behaviors: any;
+}
+
+type EditorPropertyValueType = number | string | boolean | SDK.Color;
+
+type Vec2Arr = [number, number];
+type Vec3Arr = [number, number, number];
+type Vec4Arr = [number, number, number, number];
diff --git a/spine-ts/spine-construct3/ts-defs/editor/ui/ILayoutView.d.ts b/spine-ts/spine-construct3/ts-defs/editor/ui/ILayoutView.d.ts
new file mode 100644
index 000000000..19d68abea
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/ui/ILayoutView.d.ts
@@ -0,0 +1,17 @@
+declare namespace SDK.UI {
+ class ILayoutView {
+ GetProject(): SDK.IProject;
+ GetZoomFactor(): number;
+
+ LayoutToClientDeviceX(x: number): number;
+ LayoutToClientDeviceY(y: number): number;
+
+ SetDeviceTransform(iRenderer: SDK.Gfx.IWebGLRenderer): void;
+ SetDefaultTransform(iRenderer: SDK.Gfx.IWebGLRenderer): void;
+
+ Refresh(): void;
+
+ GetLayout(): SDK.ILayout;
+ GetActiveLayer(): SDK.ILayer;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/editor/ui/Util.d.ts b/spine-ts/spine-construct3/ts-defs/editor/ui/Util.d.ts
new file mode 100644
index 000000000..9aa19fb98
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/editor/ui/Util.d.ts
@@ -0,0 +1,22 @@
+
+declare namespace SDK.UI {
+
+ interface DragDropFileImportHandlerOpts {
+ isZipFormat: boolean;
+ toLayoutView: boolean;
+ }
+
+ interface DragDropFileImportHandlerCallbackOpts {
+ layoutView: SDK.UI.ILayoutView;
+ clientX: number;
+ clientY: number;
+ layoutX: number;
+ layoutY: number;
+ }
+
+ class Util {
+ static ShowLongTextPropertyDialog(initText: string, caption: string): Promise;
+
+ static AddDragDropFileImportHandler(callback: (filename: string, file: SDK.IZipFile | Blob, opts: DragDropFileImportHandlerCallbackOpts) => Promise, opts?: DragDropFileImportHandlerOpts): void;
+ }
+}
\ No newline at end of file
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/3D camera/I3DCameraObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/3D camera/I3DCameraObjectType.d.ts
new file mode 100644
index 000000000..44bc62fc5
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/3D camera/I3DCameraObjectType.d.ts
@@ -0,0 +1,25 @@
+
+type Camera3DLayoutAxes = "x" | "y" | "z";
+type Camera3DCameraAxes = "forward" | "up" | "right";
+type Camera3DMoveType = "both" | "camera" | "look";
+
+/** Represents the 3D Camera object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/3d-camera | I3DCameraObjectType documentation } */
+declare class I3DCameraObjectType extends IObjectType
+{
+ lookAtPosition(camX: number, camY: number, camZ: number, lookX: number, lookY: number, lookZ: number, upX: number, upY: number, upZ: number): void;
+ lookParallelToLayout(camX: number, camY: number, camZ: number, lookAngle: number): void;
+ restore2DCamera(): void;
+ moveAlongLayoutAxis(distance: number, axisStr: Camera3DLayoutAxes, whichStr: Camera3DMoveType): void;
+ moveAlongCameraAxis(distance: number, axisStr: Camera3DCameraAxes, whichStr: Camera3DMoveType): void;
+ rotateCamera(rotateX: number, rotateY: number, minPolar: number, maxPolar: number): void;
+ fieldOfView: number;
+
+ getCameraPosition(): Vec3Arr;
+ getLookPosition(): Vec3Arr;
+ getUpVector(): Vec3Arr;
+ getRightVector(): Vec3Arr;
+ getForwardVector(): Vec3Arr;
+ getLookVector(): Vec3Arr;
+ readonly zScale: number;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/3D shape/I3DShapeInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/3D shape/I3DShapeInstance.d.ts
new file mode 100644
index 000000000..d4e14a542
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/3D shape/I3DShapeInstance.d.ts
@@ -0,0 +1,30 @@
+
+type Shape3DShapeType = "box" | "prism" | "wedge" | "pyramid" | "corner-out" | "corner-in";
+type Shape3DFaceType = "back" | "front" | "left" | "right" | "top" | "bottom";
+
+/** Represents the 3D Shape object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/3d-shape | I3DShapeInstance documentation } */
+declare class I3DShapeInstance extends IWorldInstance
+{
+ zHeight: number;
+ shape: Shape3DShapeType;
+ zTilingFactor: number;
+
+ getImagePointCount(): number;
+ getImagePointX(nameOrIndex: ImagePointParameter): number;
+ getImagePointY(nameOrIndex: ImagePointParameter): number;
+ getImagePointZ(nameOrIndex: ImagePointParameter): number;
+ getImagePoint(nameOrIndex: ImagePointParameter): Vec3Arr;
+
+ getFaceImagePointCount(face: Shape3DFaceType): number;
+ getFaceImagePointX(face: Shape3DFaceType, nameOrIndex: ImagePointParameter): number;
+ getFaceImagePointY(face: Shape3DFaceType, nameOrIndex: ImagePointParameter): number;
+ getFaceImagePointZ(face: Shape3DFaceType, nameOrIndex: ImagePointParameter): number;
+ getFaceImagePoint(face: Shape3DFaceType, nameOrIndex: ImagePointParameter): Vec3Arr;
+
+ setFaceVisible(face: Shape3DFaceType, isVisible: boolean): void;
+ isFaceVisible(face: Shape3DFaceType): boolean;
+ isBackFaceCulling: boolean;
+ setFaceImage(face: Shape3DFaceType, image: Shape3DFaceType): void;
+ setFaceObject(face: Shape3DFaceType, objectClass: IObjectClass): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Advanced Random/IAdvancedRandomObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Advanced Random/IAdvancedRandomObjectType.d.ts
new file mode 100644
index 000000000..93c800bb6
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Advanced Random/IAdvancedRandomObjectType.d.ts
@@ -0,0 +1,39 @@
+
+type AdvancedRandomGradientMode = "rgb" | "float";
+type AdvancedRandomProbabilityTableEntry = number | string;
+
+/** Represents the Advanced Random object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/advanced-random | IAdvancedRandomObjectType documentation } */
+declare class IAdvancedRandomObjectType extends IObjectType
+{
+ seed: string;
+ octaves: number;
+
+ classic2d(x: number, y: number): number;
+ classic3d(x: number, y: number, z: number): number;
+ billow2d(x: number, y: number): number;
+ billow3d(x: number, y: number, z: number): number;
+ ridged2d(x: number, y: number): number;
+ ridged3d(x: number, y: number, z: number): number;
+ cellular2d(x: number, y: number): number;
+ cellular3d(x: number, y: number, z: number): number;
+ voronoi2d(x: number, y: number): number;
+ voronoi3d(x: number, y: number, z: number): number;
+
+ createGradient(name: string, mode: AdvancedRandomGradientMode): void;
+ setCurrentGradient(name: string): void;
+ addGradientStop(position: number, value: number): void;
+ sampleGradient(name: string | null, value: number): number;
+
+ createProbabilityTable(name: string): void;
+ createProbabilityTableFromJSON(name: string, jsonStr: string): void;
+ getProbabilityTableAsJSON(): string;
+ setCurrentProbabilityTable(name: string): void;
+ addProbabilityTableEntry(weight: number, value: AdvancedRandomProbabilityTableEntry): void;
+ removeProbabilityTableEntry(weight: number, value: AdvancedRandomProbabilityTableEntry): void;
+ sampleProbabilityTable(name?: string): AdvancedRandomProbabilityTableEntry;
+
+ createPermutationTable(length: number, offset: number): void;
+ shufflePermutationTable(): void;
+ getPermutation(index: number): number;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Array/IArrayInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Array/IArrayInstance.d.ts
new file mode 100644
index 000000000..bc962d836
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Array/IArrayInstance.d.ts
@@ -0,0 +1,16 @@
+
+type ArrayValueType = string | number;
+
+/** Represents the Array object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/array | IArrayInstance documentation } */
+declare class IArrayInstance extends IWorldInstance
+{
+ readonly width: number;
+ readonly height: number;
+ readonly depth: number;
+
+ setSize(w: number, h?: number, d?: number): void;
+
+ getAt(x: number, y?: number, z?: number): ArrayValueType;
+ setAt(val: ArrayValueType, x: number, y?: number, z?: number): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Audio/IAudioObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Audio/IAudioObjectType.d.ts
new file mode 100644
index 000000000..b52785857
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Audio/IAudioObjectType.d.ts
@@ -0,0 +1,13 @@
+
+/** Represents the Audio object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/audio | IAudioObjectType documentation } */
+declare class IAudioObjectType extends IObjectType
+{
+ readonly audioContext: AudioContext;
+ readonly destinationNode: AudioDestinationNode;
+
+ isSilent: boolean;
+ masterVolume: number;
+
+ stopAll(): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Binary Data/IBinaryDataInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Binary Data/IBinaryDataInstance.d.ts
new file mode 100644
index 000000000..a72023587
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Binary Data/IBinaryDataInstance.d.ts
@@ -0,0 +1,23 @@
+
+/** Represents the Binary Data object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/binary-data | IBinaryDataInstance documentation } */
+declare class IBinaryDataInstance extends IWorldInstance
+{
+ /** Set the content of the Binary Data by copying the provided ArrayBuffer
+ * or typed array. */
+ setArrayBufferCopy(viewOrBuffer: ArrayBuffer | TypedArray): void;
+
+ /** Set the content of the Binary Data by assuming ownership of the
+ * provided ArrayBuffer. This does not require copying the data, but
+ * nothing else must use the provided ArrayBuffer beyond this call. */
+ setArrayBufferTransfer(arrayBuffer: ArrayBuffer): void;
+
+ /** Get the content of the Binary Data object by copying its internal
+ * ArrayBuffer. The returned data is safe to modify. */
+ getArrayBufferCopy(): ArrayBuffer;
+
+ /** Get the content of the Binary Data object by returning a reference
+ * to its internal ArrayBuffer. This is only safe to read - it must not
+ * be modified in any way. If modification is necessary, use getArrayBufferCopy(). */
+ getArrayBufferReadOnly(): ArrayBuffer;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Button/IButtonInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Button/IButtonInstance.d.ts
new file mode 100644
index 000000000..d1cf09d2b
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Button/IButtonInstance.d.ts
@@ -0,0 +1,17 @@
+
+interface ButtonInstanceEventMap extends WorldInstanceEventMap {
+ "click": InstanceEvent;
+}
+
+/** Represents the Button object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/button | IButtonInstance documentation } */
+declare class IButtonInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: ButtonInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: ButtonInstanceEventMap[K]) => any): void;
+
+ text: string;
+ tooltip: string;
+ isEnabled: boolean;
+ isChecked: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/CSV/ICSVObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/CSV/ICSVObjectType.d.ts
new file mode 100644
index 000000000..cabd4a774
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/CSV/ICSVObjectType.d.ts
@@ -0,0 +1,11 @@
+
+type CsvDataType = "auto" | "string" | "number";
+
+/** Represents the CSV object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/csv | ICSVObjectType documentation } */
+declare class ICSVObjectType extends IObjectType
+{
+ parseCsv(str: string, delimiter?: string, dataType?: CsvDataType): any[];
+
+ generateCsv(arr: any[], delimiter?: string): string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Construct Game Services/ICGSObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Construct Game Services/ICGSObjectType.d.ts
new file mode 100644
index 000000000..d85ad69ab
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Construct Game Services/ICGSObjectType.d.ts
@@ -0,0 +1,54 @@
+
+/** Represents the Construct Game Services object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/construct-game-services | ICGSObjectType documentation } */
+
+type CGSSignInProvider = "Apple" | "BattleNet" | "BattleNetChina" | "Discord" | "Facebook" | "Github" | "Google" | "ItchIO" | "Microsoft" | "Reddit" | "Steam" | "X" | "Yandex";
+
+interface CGSSignInOptions {
+ expiryMins?: number;
+ popupWindowWidth?: number;
+ popupWindowHeight?: number;
+}
+
+type CGSLeaderboardScoreRange = "Daily" | "Weekly" | "Monthly" | "Yearly";
+
+interface CGSGetLeaderboardScoresOptions {
+ resultsPerPage?: number;
+ page?: number;
+ country?: string;
+ range?: CGSLeaderboardScoreRange;
+ rangeOffset?: number;
+ culture?: string;
+}
+
+interface CGSLeaderboardScoreResult {
+ score: number;
+ formattedScore: string;
+ rank: number;
+ formattedRank: string;
+ country: string;
+ playerId: string;
+ playerName: string;
+}
+
+interface CGSLeaderboardScoreResults {
+ totalPageCount: number;
+ scores: CGSLeaderboardScoreResult[];
+}
+
+declare class ICGSObjectType extends IObjectType>
+{
+ readonly isSignedIn: boolean;
+ readonly canSignInPersistent: boolean;
+ readonly playerId: string;
+ readonly playerName: string;
+ readonly gameId: string;
+ readonly sessionKey: string;
+
+ signInWithProvider(provider: CGSSignInProvider, gameId: string, opts?: CGSSignInOptions): Promise;
+ signInPersistent(gameId: string): Promise;
+ signOut(): Promise;
+
+ submitScore(score: number, leaderboardId?: string): Promise;
+ getLeaderboardScores(leaderboardId: string, opts?: CGSGetLeaderboardScoresOptions): Promise;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Dictionary/IDictionaryInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Dictionary/IDictionaryInstance.d.ts
new file mode 100644
index 000000000..277c9745d
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Dictionary/IDictionaryInstance.d.ts
@@ -0,0 +1,9 @@
+
+type DictionaryValueType = string | number;
+
+/** Represents the Dictionary object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/dictionary | IDictionaryInstance documentation } */
+declare class IDictionaryInstance extends IWorldInstance
+{
+ getDataMap(): Map;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Drawing canvas/IDrawingCanvasInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Drawing canvas/IDrawingCanvasInstance.d.ts
new file mode 100644
index 000000000..374232ace
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Drawing canvas/IDrawingCanvasInstance.d.ts
@@ -0,0 +1,44 @@
+
+type DrawingCanvasGradientDirection = "horizontal" | "vertical";
+type DrawingCanvasLineCap = "butt" | "square";
+type DrawingCanvasColor = Vec3Arr | Vec4Arr;
+type DrawingCanvasPoly = Array>;
+
+interface DrawingCanvasInstanceEventMap extends WorldInstanceEventMap {
+ "resolutionchange": InstanceEvent;
+}
+
+/** Represents the Drawing Canvas object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/drawing-canvas | IDrawingCanvasInstance documentation } */
+declare class IDrawingCanvasInstance extends IWorldInstance
+{
+ addEventListener>(type: K, listener: (ev: DrawingCanvasInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: DrawingCanvasInstanceEventMap[K]) => any): void;
+
+ readonly pixelScale: number;
+ readonly surfaceDeviceWidth: number;
+ readonly surfaceDeviceHeight: number;
+ getSurfaceDeviceSize(): Vec2Arr;
+ setFixedResolutionMode(fixedWidth: number, fixedHeight: number): void;
+ setAutoResolutionMode(): void;
+
+ clearCanvas(color: DrawingCanvasColor): void;
+ clearRect(left: number, top: number, right: number, bottom: number, color: DrawingCanvasColor): void;
+ fillRect(left: number, top: number, right: number, bottom: number, color: DrawingCanvasColor): void;
+ fillLinearGradient(left: number, top: number, right: number, bottom: number, color1: DrawingCanvasColor, color2: DrawingCanvasColor, dirStr?: DrawingCanvasGradientDirection): void;
+ fillEllipse(x: number, y: number, radiusX: number, radiusY: number, color: DrawingCanvasColor, isSmooth?: boolean): void;
+ outlineEllipse(x: number, y: number, radiusX: number, radiusY: number, color: DrawingCanvasColor, thickness: number, isSmooth?: boolean): void;
+
+ outlineRect(left: number, top: number, right: number, bottom: number, color: DrawingCanvasColor, thickness: number): void;
+ line(x1: number, y1: number, x2: number, y2: number, color: DrawingCanvasColor, thickness: number, capStr?: DrawingCanvasLineCap): void;
+ lineDashed(x1: number, y1: number, x2: number, y2: number, color: DrawingCanvasColor, thickness: number, dashLength: number, capStr?: DrawingCanvasLineCap): void;
+ linePoly(polyArr: DrawingCanvasPoly, color: DrawingCanvasColor, thickness: number, capStr?: DrawingCanvasLineCap): void;
+ lineDashedPoly(polyArr: DrawingCanvasPoly, color: DrawingCanvasColor, thickness: number, dashLength: number, capStr?: DrawingCanvasLineCap): void;
+ fillPoly(polyArr: DrawingCanvasPoly, color: DrawingCanvasColor, isConvex?: boolean): void;
+ setDrawBlend(blendMode: BlendModeParameter): void;
+
+ pasteInstances(instances: IWorldInstance[], includeFx?: boolean): Promise;
+ getImagePixelData(): Promise;
+ loadImagePixelData(imageData: ImageData, premultiplyAlpha?: boolean): void;
+ saveImage(format?: string, quality?: number, areaRect?: DOMRect): Promise;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Facebook/IFacebookObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Facebook/IFacebookObjectType.d.ts
new file mode 100644
index 000000000..b13f4dbf0
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Facebook/IFacebookObjectType.d.ts
@@ -0,0 +1,6 @@
+
+/** Represents the Facebook object. */
+declare class IFacebookObjectType extends IObjectType
+{
+ getAccessToken(): string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/File chooser/IFileChooserInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/File chooser/IFileChooserInstance.d.ts
new file mode 100644
index 000000000..d39be4ad8
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/File chooser/IFileChooserInstance.d.ts
@@ -0,0 +1,21 @@
+
+interface FileChooserChangeEvent extends InstanceEvent {
+ files: File[];
+}
+
+interface FileChooserInstanceEventMap extends WorldInstanceEventMap {
+ "change": FileChooserChangeEvent;
+}
+
+/** Represents the File Chooser object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/file-chooser | IFileChooserInstance documentation } */
+declare class IFileChooserInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: FileChooserInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: FileChooserInstanceEventMap[K]) => any): void;
+
+ click(): void;
+ clear(): void;
+
+ getFiles(): File[];
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/HTML Element/IHTMLElementInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/HTML Element/IHTMLElementInstance.d.ts
new file mode 100644
index 000000000..e1f8fa544
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/HTML Element/IHTMLElementInstance.d.ts
@@ -0,0 +1,41 @@
+
+type HTMLContentType = "html" | "bbcode" | "text";
+type HTMLSetClassMode = "add" | "toggle" | "remove";
+type HTMLSetAttributeMode = "set" | "remove";
+type HTMLInsertAtType = "start" | "end" | "replace";
+type HTMLScrollDirectionType = "left" | "top";
+
+interface HTMLInstanceElementEvent extends InstanceEvent {
+ targetId: string;
+ targetClass: string;
+}
+
+interface HTMLInstanceAnimationEvent extends HTMLInstanceElementEvent {
+ animationName: string;
+}
+
+interface HTMLInstanceEventMap extends WorldInstanceEventMap {
+ "click": HTMLInstanceElementEvent;
+ "animationend": HTMLInstanceAnimationEvent;
+}
+
+/** Represents the HTML Element object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/html-element | IHTMLElementInstance documentation } */
+declare class IHTMLElementInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: HTMLInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: HTMLInstanceEventMap[K]) => any): void;
+
+ setContent(str: string, type?: HTMLContentType, selector?: string, isAll?: boolean): Promise;
+ insertContent(str: string, type?: HTMLContentType, atEnd?: boolean, selector?: string, isAll?: boolean): Promise;
+ setContentClass(mode: HTMLSetClassMode, classArr: string | string[], selector: string, isAll?: boolean): Promise;
+ setContentAttribute(mode: HTMLSetAttributeMode, attrib: string, value: string, selector: string, isAll?: boolean): Promise;
+ setContentCssStyle(propName: string, value: string, selector: string, isAll?: boolean) : Promise;
+
+ positionInstanceAtElement(inst: IWorldInstance, selector: string): Promise;
+ createSpriteImgElement(spriteInst: ISpriteInstance, selector: string, insertAt: HTMLInsertAtType, id?: string, class_?: string): Promise;
+ setScrollPosition(selector: string, direction: HTMLScrollDirectionType, position: number): Promise;
+
+ htmlContent: string;
+ textContent: string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Internationalization/IInternationalizationObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Internationalization/IInternationalizationObjectType.d.ts
new file mode 100644
index 000000000..226edb321
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Internationalization/IInternationalizationObjectType.d.ts
@@ -0,0 +1,26 @@
+
+type I18nPlaceholderType = string | number;
+
+declare class I18NLookupContext
+{
+ lookup(context: string, ...args: I18nPlaceholderType[]): string;
+ lookupPlural(context: string, count: number, ...args: I18nPlaceholderType[]): string;
+ createContext(context: string): I18NLookupContext;
+}
+
+declare class IInternationalizationObjectType extends IObjectType
+{
+ locale: string;
+
+ addString(context: string, str: string): void;
+ saveToJSONString(): string;
+ loadFromJSONString(jsonStr: string): void;
+
+ setContext(context: string): void;
+ getContext(): string;
+ pushContext(context: string): void;
+ popContext(): void;
+ createContext(context: string): I18NLookupContext;
+ lookup(context: string, ...args: I18nPlaceholderType[]): string;
+ lookupPlural(context: string, count: number, ...args: I18nPlaceholderType[]): string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/JSON/IJSONInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/JSON/IJSONInstance.d.ts
new file mode 100644
index 000000000..84e6b9798
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/JSON/IJSONInstance.d.ts
@@ -0,0 +1,12 @@
+
+/** Represents the JSON object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/json | IJSONInstance documentation } */
+declare class IJSONInstance extends IWorldInstance
+{
+ getJsonDataCopy(): any;
+ setJsonDataCopy(o: any): void;
+ setJsonString(str: string): void;
+
+ toCompactString(): string;
+ toBeautifiedString(): string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Keyboard/IKeyboardObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Keyboard/IKeyboardObjectType.d.ts
new file mode 100644
index 000000000..ea882aff6
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Keyboard/IKeyboardObjectType.d.ts
@@ -0,0 +1,9 @@
+
+type KeyboardKeyOrCode = number | string;
+
+/** Represents the Keyboard object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/keyboard | IKeyboardObjectType documentation } */
+declare class IKeyboardObjectType extends IObjectType
+{
+ isKeyDown(keyOrCode: KeyboardKeyOrCode): boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/List/IListInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/List/IListInstance.d.ts
new file mode 100644
index 000000000..10f571c12
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/List/IListInstance.d.ts
@@ -0,0 +1,29 @@
+
+interface ListInstanceEventMap extends WorldInstanceEventMap {
+ "click": InstanceEvent;
+ "dblclick": InstanceEvent;
+ "selectionchange": InstanceEvent;
+}
+
+/** Represents the List object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/list | IListInstance documentation } */
+declare class IListInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: ListInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: ListInstanceEventMap[K]) => any): void;
+
+ tooltip: string;
+ readonly itemCount: number;
+
+ addItem(text: string): void;
+ insertItem(index: number, text: string): void;
+ setItemText(index: number, text: string): void;
+ getItemText(index: number): string;
+ removeItem(index: number): void;
+ clear(): void;
+
+ selectedIndex: number;
+ readonly selectedCount: number;
+ getSelectedIndexAt(index: number): number;
+ getSelectedTextAt(index: number): string;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Mouse/IMouseObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Mouse/IMouseObjectType.d.ts
new file mode 100644
index 000000000..9bcb586e7
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Mouse/IMouseObjectType.d.ts
@@ -0,0 +1,13 @@
+
+/** Represents the Mouse object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/mouse | IMouseObjectType documentation } */
+declare class IMouseObjectType extends IObjectType
+{
+ getMouseX(layerNameOrNumber?: LayerParameter): number;
+ getMouseY(layerNameOrNumber?: LayerParameter): number;
+ getMousePosition(layerNameOrNumber?: LayerParameter): Vec2Arr;
+ isMouseButtonDown(button: number): boolean;
+
+ setCursorStyle(cursorStyle: string): void;
+ setCursorObjectClass(objectClass: IObjectClass): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerObjectType.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerObjectType.d.ts
new file mode 100644
index 000000000..e60939148
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerObjectType.d.ts
@@ -0,0 +1,88 @@
+
+type MultiplayerTransmissionMode = "o" | "r" | "u";
+type MultiplayerMessageType = string | JSONValue | ArrayBuffer;
+type MultiplayerTransferDirection = "send" | "receive";
+
+interface MultiplayerPeerEvent extends ConstructEvent {
+ peerId: string;
+ peerAlias: string;
+}
+
+interface MultiplayerPeerDisconnectEvent extends MultiplayerPeerEvent {
+ leaveReason: string;
+}
+
+interface MultiplayerMessageEvent extends ConstructEvent {
+ fromId: string;
+ fromAlias: string;
+ message: JSONValue | ArrayBuffer;
+ transmissionMode: MultiplayerTransmissionMode;
+}
+
+interface MultiplayerBinaryTransferProgressEvent extends ConstructEvent {
+ peerId: string;
+ peerAlias: string;
+ direction: MultiplayerTransferDirection;
+ tag: string;
+ progress: number;
+}
+
+interface MultiplayerBinaryTransferEvent extends ConstructEvent {
+ peerId: string;
+ peerAlias: string;
+ direction: MultiplayerTransferDirection;
+ tag: string;
+}
+
+interface MultiplayerBinaryTransferStartEvent extends MultiplayerBinaryTransferEvent {
+ mimeType: string;
+ fileName: string;
+ size: number;
+}
+
+interface MultiplayerBinaryTransferCompleteEvent extends MultiplayerBinaryTransferStartEvent {
+ data: File | Blob | ArrayBuffer | null;
+}
+
+interface MultiplayerObjectEventMap {
+ "peerconnect": MultiplayerPeerEvent;
+ "peerdisconnect": MultiplayerPeerDisconnectEvent;
+ "message": MultiplayerMessageEvent;
+ "kicked": ConstructEvent;
+ "binarytransferstart": MultiplayerBinaryTransferStartEvent,
+ "binarytransferprogress": MultiplayerBinaryTransferProgressEvent,
+ "binarytransfercancelled": MultiplayerBinaryTransferEvent,
+ "binarytransfercomplete": MultiplayerBinaryTransferCompleteEvent
+}
+
+interface TransferPeerBinaryOpts {
+ tag?: string;
+ signal?: AbortSignal;
+}
+
+/** Represents the Multiplayer object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/multiplayer | IMultiplayerObjectType documentation } */
+declare class IMultiplayerObjectType extends IObjectType>
+{
+ readonly signalling: MultiplayerSignallingState;
+ readonly stats: MultiplayerStats;
+
+ readonly isHost: boolean;
+ readonly myAlias: string;
+ readonly myId: string;
+ readonly hostAlias: string;
+ readonly hostId: string;
+ readonly currentGame: string;
+ readonly currentGameInstance: string;
+ readonly currentRoom: string;
+
+ readonly peerCount: number;
+ getAllPeers(): IMultiplayerPeer[];
+ getPeerById(id: string): IMultiplayerPeer | null;
+ sendPeerMessage(peerId: string, message: MultiplayerMessageType, transmissionMode?: MultiplayerTransmissionMode): void;
+ transferPeerBinary(peerId: string, data: File | Blob | ArrayBuffer, opts?: TransferPeerBinaryOpts): Promise;
+ hostBroadcastMessage(fromId: string | null, message: MultiplayerMessageType, transmissionMode?: MultiplayerTransmissionMode): void;
+
+ disconnectRoom(): void;
+ simulateLatency(latency: number, pdv: number, loss: number): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerPeer.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerPeer.d.ts
new file mode 100644
index 000000000..986181a14
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/IMultiplayerPeer.d.ts
@@ -0,0 +1,15 @@
+
+/** Represents a peer in the Multiplayer object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/multiplayer | IMultiplayerObjectType documentation } */
+declare class IMultiplayerPeer
+{
+ readonly id: string;
+ readonly alias: string;
+ readonly isHost: boolean;
+ readonly isMe: boolean;
+
+ readonly latency: number;
+ readonly pdv: number;
+
+ send(message: MultiplayerMessageType, transmissionMode?: MultiplayerTransmissionMode): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerSignallingState.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerSignallingState.d.ts
new file mode 100644
index 000000000..5baed1c3a
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerSignallingState.d.ts
@@ -0,0 +1,74 @@
+
+type MultiplayerRoomListType = "all" | "unlocked" | "available";
+type MultiplayerRoomState = "available" | "locked" | "full";
+
+interface MultiplayerSignallingServerState {
+ myId: string;
+ serverVersion: string;
+ serverName: string;
+ serverOperator: string;
+ serverMOTD: string;
+}
+
+interface MultiplayerSignallingLoginResult {
+ myAlias: string;
+}
+
+interface MultiplayerSignallingJoinResult {
+ isHost: boolean;
+ hostId: string;
+ hostAlias: string;
+}
+
+interface MultiplayerSignallingAutoJoinResult {
+ isHost: boolean;
+ hostId: string;
+ hostAlias: string;
+ room: string;
+}
+
+interface MultiplayerSignallingGameInstanceEntry {
+ name: string;
+ peerCount: number;
+}
+
+interface MultiplayerSignallingRoomEntry {
+ name: string;
+ peerCount: number;
+ maxPeerCount: number;
+ state: MultiplayerRoomState;
+}
+
+interface MultiplayerErrorEvent extends ConstructEvent {
+ message: string;
+}
+
+interface MultiplayerSignallingEventMap {
+ "connected": MultiplayerSignallingServerState;
+ "login": MultiplayerSignallingLoginResult;
+ "join": MultiplayerSignallingAutoJoinResult;
+ "leave": ConstructEvent;
+ "disconnected": ConstructEvent;
+ "kicked": ConstructEvent;
+ "error": MultiplayerErrorEvent;
+}
+
+/** Represents the signalling state for the Multiplayer object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/multiplayer | IMultiplayerObjectType documentation } */
+declare class MultiplayerSignallingState extends ConstructEventTarget
+{
+ addICEServer(url: string, username?: string, credential?: string): void;
+ connect(url?: string): Promise;
+ readonly isConnected: boolean;
+ disconnect(): void;
+
+ login(alias: string): Promise;
+ readonly isLoggedIn: boolean;
+
+ joinRoom(game: string, instance: string, room: string, maxClients?: number): Promise;
+ autoJoinRoom(game: string, instance: string, room: string, maxClients?: number, isLocking?: boolean): Promise;
+ leaveRoom(): Promise;
+
+ requestGameInstanceList(game: string): Promise;
+ requestRoomList(game: string, instance: string, type: MultiplayerRoomListType): Promise;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerStats.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerStats.d.ts
new file mode 100644
index 000000000..e3f83a3c3
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Multiplayer/MultiplayerStats.d.ts
@@ -0,0 +1,13 @@
+
+/** Represents statistics for the Multiplayer object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/multiplayer | IMultiplayerObjectType documentation } */
+declare class MultiplayerStats
+{
+ readonly outboundCount: number;
+ readonly outboundBandwidth: number;
+ readonly outboundDecompressedBandwidth: number;
+
+ readonly inboundCount: number;
+ readonly inboundBandwidth: number;
+ readonly inboundDecompressedBandwidth: number;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Particles/IParticlesInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Particles/IParticlesInstance.d.ts
new file mode 100644
index 000000000..22a00ae34
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Particles/IParticlesInstance.d.ts
@@ -0,0 +1,26 @@
+
+/** Represents the Particles object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/particles | IParticlesInstance documentation } */
+declare class IParticlesInstance extends IWorldInstance
+{
+ isSpraying: boolean;
+ rate: number;
+ sprayCone: number;
+ initSpeed: number;
+ initSize: number;
+ initOpacity: number;
+ initXRandom: number;
+ initYRandom: number;
+ initSpeedRandom: number;
+ initSizeRandom: number;
+ initGrowRate: number;
+ initGrowRandom: number;
+ acceleration: number;
+ gravity: number;
+ lifeAngleRandom: number;
+ lifeSpeedRandom: number;
+ lifeOpacityRandom: number;
+ timeout: number;
+ fastForward(time: number): void;
+ setParticleObjectClass(objectClass?: IObjectType): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Progress bar/IProgressBarInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Progress bar/IProgressBarInstance.d.ts
new file mode 100644
index 000000000..69fd1af48
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Progress bar/IProgressBarInstance.d.ts
@@ -0,0 +1,16 @@
+
+interface ProgressInstanceEventMap extends WorldInstanceEventMap {
+ "click": InstanceEvent;
+}
+/** Represents the Progress Bar object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/progress-bar | IProgressBarInstance documentation } */
+declare class IProgressBarInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: ProgressInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: ProgressInstanceEventMap[K]) => any): void;
+
+ progress: number;
+ maximum: number;
+ tooltip: string;
+ setIndeterminate(): void;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/QR code/IQRCodeInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/QR code/IQRCodeInstance.d.ts
new file mode 100644
index 000000000..0fd6ea792
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/QR code/IQRCodeInstance.d.ts
@@ -0,0 +1,8 @@
+
+type QRCodeCorrectionLevel = "l" | "m" | "q" | "h";
+
+declare class IQRCodeInstance extends IWorldInstance
+{
+ text: string;
+ correctionLevel: QRCodeCorrectionLevel;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/SVG Picture/ISVGPictureInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/SVG Picture/ISVGPictureInstance.d.ts
new file mode 100644
index 000000000..54a418871
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/SVG Picture/ISVGPictureInstance.d.ts
@@ -0,0 +1,9 @@
+
+/** Represents the SVG Picture object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/svg-picture | ISVGPictureInstance documentation } */
+declare class ISVGPictureInstance extends IWorldInstance
+{
+ svgUrl: string;
+
+ setSvgUrl(url: string): Promise;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Shadow light/IShadowLightInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Shadow light/IShadowLightInstance.d.ts
new file mode 100644
index 000000000..5837b1336
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Shadow light/IShadowLightInstance.d.ts
@@ -0,0 +1,14 @@
+
+type ShadowLightCastFromMode = "all" | "same-tag" | "different-tag";
+
+/** Represents the Shadow Light object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/shadow-light | IShadowLightInstance documentation } */
+declare class IShadowLightInstance extends IWorldInstance
+{
+ lightX: number;
+ lightY: number;
+ lightHeight: number;
+ shadowColor: Vec3Arr;
+ tag: string;
+ castFrom: ShadowLightCastFromMode;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Slider bar/ISliderBarInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Slider bar/ISliderBarInstance.d.ts
new file mode 100644
index 000000000..e34182a7f
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Slider bar/ISliderBarInstance.d.ts
@@ -0,0 +1,21 @@
+
+interface SliderBarInstanceEventMap extends WorldInstanceEventMap {
+ "click": InstanceEvent;
+ "change": InstanceEvent;
+ "input": InstanceEvent;
+}
+
+/** Represents the Slider Bar object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/slider-bar | ISliderBarInstance documentation } */
+declare class ISliderBarInstance extends IDOMInstance
+{
+ addEventListener>(type: K, listener: (ev: SliderBarInstanceEventMap[K]) => any): void;
+ removeEventListener>(type: K, listener: (ev: SliderBarInstanceEventMap[K]) => any): void;
+
+ value: number;
+ maximum: number;
+ minimum: number;
+ step: number;
+ tooltip: string;
+ isEnabled: boolean;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Sprite font/ISpriteFontInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Sprite font/ISpriteFontInstance.d.ts
new file mode 100644
index 000000000..6f4d1ad81
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Sprite font/ISpriteFontInstance.d.ts
@@ -0,0 +1,23 @@
+
+/** Represents the Sprite Font object.
+ * @see {@link https://www.construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/spritefont | ISpriteFontInstance documentation } */
+declare class ISpriteFontInstance extends IWorldInstance
+{
+ text: string;
+
+ typewriterText(str: string, duration: number): void;
+ characterScale: number;
+ characterSpacing: number;
+ lineHeight: number;
+ horizontalAlign: TextAlignHorizontalMode;
+ verticalAlign: TextAlignVerticalMode;
+ wordWrapMode: TextWordWrapMode;
+ readAloud: boolean;
+ readonly textWidth: number;
+ readonly textHeight: number;
+ getTextSize(): Vec2Arr;
+ hasTagAtPosition(tag: string, x: number, y: number): boolean;
+ getTagAtPosition(x: number, y: number): string;
+ getTagCount(tag: string): number;
+ getTagPositionAndSize(tag: string, index?: number): TextFragmentPositionAndSize;
+}
diff --git a/spine-ts/spine-construct3/ts-defs/plugins/Sprite/ISpriteInstance.d.ts b/spine-ts/spine-construct3/ts-defs/plugins/Sprite/ISpriteInstance.d.ts
new file mode 100644
index 000000000..f5f3360ec
--- /dev/null
+++ b/spine-ts/spine-construct3/ts-defs/plugins/Sprite/ISpriteInstance.d.ts
@@ -0,0 +1,53 @@
+
+type SpriteAnimationFromMode = "current-frame" | "beginning";
+
+interface SpriteFrameChangeEvent extends InstanceEvent {
+ animationName: string;
+ animationFrame: number;
+}
+
+interface SpriteAnimationEndEvent extends InstanceEvent {
+ animationName: string;
+}
+
+interface SpriteInstanceEventMap