aether-engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +15 -0
  2. package/biome.json +51 -0
  3. package/bun.lock +192 -0
  4. package/index.ts +1 -0
  5. package/package.json +25 -0
  6. package/serve.ts +125 -0
  7. package/src/audio/AudioEngine.ts +61 -0
  8. package/src/components/Animator3D.ts +65 -0
  9. package/src/components/AudioSource.ts +26 -0
  10. package/src/components/BitmapText.ts +25 -0
  11. package/src/components/Camera.ts +33 -0
  12. package/src/components/CameraFollow.ts +5 -0
  13. package/src/components/Collider.ts +16 -0
  14. package/src/components/Components.test.ts +68 -0
  15. package/src/components/Light.ts +15 -0
  16. package/src/components/MeshRenderer.ts +58 -0
  17. package/src/components/ParticleEmitter.ts +59 -0
  18. package/src/components/RigidBody.ts +9 -0
  19. package/src/components/ShadowCaster.ts +3 -0
  20. package/src/components/SkinnedMeshRenderer.ts +25 -0
  21. package/src/components/SpriteAnimator.ts +42 -0
  22. package/src/components/SpriteRenderer.ts +26 -0
  23. package/src/components/Transform.test.ts +39 -0
  24. package/src/components/Transform.ts +54 -0
  25. package/src/core/AssetManager.ts +123 -0
  26. package/src/core/Input.test.ts +67 -0
  27. package/src/core/Input.ts +94 -0
  28. package/src/core/Scene.ts +24 -0
  29. package/src/core/SceneManager.ts +57 -0
  30. package/src/core/Storage.ts +161 -0
  31. package/src/desktop/SteamClient.ts +52 -0
  32. package/src/ecs/System.ts +11 -0
  33. package/src/ecs/World.test.ts +29 -0
  34. package/src/ecs/World.ts +149 -0
  35. package/src/index.ts +115 -0
  36. package/src/math/Color.ts +100 -0
  37. package/src/math/Vector2.ts +96 -0
  38. package/src/math/Vector3.ts +103 -0
  39. package/src/math/math.test.ts +168 -0
  40. package/src/renderer/GlowMaterial.ts +66 -0
  41. package/src/renderer/LitMaterial.ts +337 -0
  42. package/src/renderer/Material.test.ts +23 -0
  43. package/src/renderer/Material.ts +80 -0
  44. package/src/renderer/OcclusionMaterial.ts +43 -0
  45. package/src/renderer/ParticleMaterial.ts +66 -0
  46. package/src/renderer/Shader.ts +44 -0
  47. package/src/renderer/SkinnedLitMaterial.ts +55 -0
  48. package/src/renderer/WaterMaterial.ts +298 -0
  49. package/src/renderer/WebGLRenderer.ts +917 -0
  50. package/src/systems/Animation3DSystem.ts +148 -0
  51. package/src/systems/AnimationSystem.ts +58 -0
  52. package/src/systems/AudioSystem.ts +62 -0
  53. package/src/systems/LightingSystem.ts +114 -0
  54. package/src/systems/ParticleSystem.ts +278 -0
  55. package/src/systems/PhysicsSystem.ts +211 -0
  56. package/src/systems/Systems.test.ts +165 -0
  57. package/src/systems/TextSystem.ts +153 -0
  58. package/src/ui/AnimationEditor.tsx +639 -0
  59. package/src/ui/BottomPanel.tsx +443 -0
  60. package/src/ui/EntityExplorer.tsx +420 -0
  61. package/src/ui/GameState.ts +286 -0
  62. package/src/ui/Icons.tsx +239 -0
  63. package/src/ui/InventoryPanel.tsx +335 -0
  64. package/src/ui/PlayerHUD.tsx +250 -0
  65. package/src/ui/SpriteEditor.tsx +3241 -0
  66. package/src/ui/SpriteSheetManager.tsx +198 -0
  67. package/src/utils/GLTFLoader.ts +257 -0
  68. package/src/utils/ObjLoader.ts +81 -0
  69. package/src/utils/idb.ts +137 -0
  70. package/src/utils/packer.ts +85 -0
  71. package/test_obj.ts +12 -0
  72. package/tsconfig.json +21 -0
  73. package/tsconfig.tsbuildinfo +1 -0
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # aether
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.2.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
package/biome.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "indentStyle": "tab"
14
+ },
15
+ "linter": {
16
+ "enabled": true,
17
+ "rules": {
18
+ "recommended": true,
19
+ "a11y": {
20
+ "useButtonType": "off",
21
+ "noLabelWithoutControl": "off",
22
+ "noStaticElementInteractions": "off",
23
+ "useKeyWithClickEvents": "off",
24
+ "useKeyWithMouseEvents": "off",
25
+ "useAltText": "off",
26
+ "noSvgWithoutTitle": "off",
27
+ "useHtmlLang": "off"
28
+ },
29
+ "suspicious": {
30
+ "noExplicitAny": "off",
31
+ "noImplicitAnyLet": "off"
32
+ },
33
+ "style": {
34
+ "noNonNullAssertion": "off"
35
+ }
36
+ }
37
+ },
38
+ "javascript": {
39
+ "formatter": {
40
+ "quoteStyle": "double"
41
+ }
42
+ },
43
+ "assist": {
44
+ "enabled": true,
45
+ "actions": {
46
+ "source": {
47
+ "organizeImports": "on"
48
+ }
49
+ }
50
+ }
51
+ }
package/bun.lock ADDED
@@ -0,0 +1,192 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "aether",
6
+ "dependencies": {
7
+ "@gltf-transform/core": "^4.3.0",
8
+ "@tauri-apps/api": "^2.10.1",
9
+ "gl-matrix": "^3.4.4",
10
+ "solid-js": "^1.9.12",
11
+ },
12
+ "devDependencies": {
13
+ "@biomejs/biome": "^2.4.10",
14
+ "@types/bun": "latest",
15
+ "@types/gl-matrix": "^3.2.0",
16
+ "@types/pngjs": "^6.0.5",
17
+ "bun-plugin-solid": "^1.0.0",
18
+ "pngjs": "^7.0.0",
19
+ },
20
+ "peerDependencies": {
21
+ "typescript": "^5",
22
+ },
23
+ },
24
+ },
25
+ "packages": {
26
+ "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
27
+
28
+ "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="],
29
+
30
+ "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
31
+
32
+ "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
33
+
34
+ "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
35
+
36
+ "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
37
+
38
+ "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow=="],
39
+
40
+ "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
41
+
42
+ "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="],
43
+
44
+ "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
45
+
46
+ "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
47
+
48
+ "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "^7.27.1" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="],
49
+
50
+ "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="],
51
+
52
+ "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.28.6", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg=="],
53
+
54
+ "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="],
55
+
56
+ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
57
+
58
+ "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
59
+
60
+ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
61
+
62
+ "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="],
63
+
64
+ "@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="],
65
+
66
+ "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="],
67
+
68
+ "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="],
69
+
70
+ "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="],
71
+
72
+ "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw=="],
73
+
74
+ "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="],
75
+
76
+ "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
77
+
78
+ "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="],
79
+
80
+ "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
81
+
82
+ "@biomejs/biome": ["@biomejs/biome@2.4.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.10", "@biomejs/cli-darwin-x64": "2.4.10", "@biomejs/cli-linux-arm64": "2.4.10", "@biomejs/cli-linux-arm64-musl": "2.4.10", "@biomejs/cli-linux-x64": "2.4.10", "@biomejs/cli-linux-x64-musl": "2.4.10", "@biomejs/cli-win32-arm64": "2.4.10", "@biomejs/cli-win32-x64": "2.4.10" }, "bin": { "biome": "bin/biome" } }, "sha512-xxA3AphFQ1geij4JTHXv4EeSTda1IFn22ye9LdyVPoJU19fNVl0uzfEuhsfQ4Yue/0FaLs2/ccVi4UDiE7R30w=="],
83
+
84
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vuzzI1cWqDVzOMIkYyHbKqp+AkQq4K7k+UCXWpkYcY/HDn1UxdsbsfgtVpa40shem8Kax4TLDLlx8kMAecgqiw=="],
85
+
86
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-14fzASRo+BPotwp7nWULy2W5xeUyFnTaq1V13Etrrxkrih+ez/2QfgFm5Ehtf5vSjtgx/IJycMMpn5kPd5ZNaA=="],
87
+
88
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-7MH1CMW5uuxQ/s7FLST63qF8B3Hgu2HRdZ7tA1X1+mk+St4JOuIrqdhIBnnyqeyWJNI+Bww7Es5QZ0wIc1Cmkw=="],
89
+
90
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-WrJY6UuiSD/Dh+nwK2qOTu8kdMDlLV3dLMmychIghHPAysWFq1/DGC1pVZx8POE3ZkzKR3PUUnVrtZfMfaJjyQ=="],
91
+
92
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-tZLvEEi2u9Xu1zAqRjTcpIDGVtldigVvzug2fTuPG0ME/g8/mXpRPcNgLB22bGn6FvLJpHHnqLnwliOu8xjYrg=="],
93
+
94
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.10", "", { "os": "linux", "cpu": "x64" }, "sha512-kDTi3pI6PBN6CiczsWYOyP2zk0IJI08EWEQyDMQWW221rPaaEz6FvjLhnU07KMzLv8q3qSuoB93ua6inSQ55Tw=="],
95
+
96
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-umwQU6qPzH+ISTf/eHyJ/QoQnJs3V9Vpjz2OjZXe9MVBZ7prgGafMy7yYeRGnlmDAn87AKTF3Q6weLoMGpeqdQ=="],
97
+
98
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.10", "", { "os": "win32", "cpu": "x64" }, "sha512-aW/JU5GuyH4uxMrNYpoC2kjaHlyJGLgIa3XkhPEZI0uKhZhJZU8BuEyJmvgzSPQNGozBwWjC972RaNdcJ9KyJg=="],
99
+
100
+ "@gltf-transform/core": ["@gltf-transform/core@4.3.0", "", { "dependencies": { "property-graph": "^4.0.0" } }, "sha512-ZeaQfszGJ9LYwELszu45CuDQCsE26lJNNe36FVmN8xclaT6WDdCj7fwGpQXo0/l/YgAVAHX+uO7YNBW75/SRYw=="],
101
+
102
+ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
103
+
104
+ "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
105
+
106
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
107
+
108
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
109
+
110
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
111
+
112
+ "@tauri-apps/api": ["@tauri-apps/api@2.10.1", "", {}, "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw=="],
113
+
114
+ "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
115
+
116
+ "@types/gl-matrix": ["@types/gl-matrix@3.2.0", "", { "dependencies": { "gl-matrix": "*" } }, "sha512-CY4JAtSOGQX7rVgqVuOk7ZfaLv8VeadDMPj3smMOy8Hp/YiHONa3Mr0mEUgbo0eEwV7+Owpf6BwspcA7hv4NXg=="],
117
+
118
+ "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
119
+
120
+ "@types/pngjs": ["@types/pngjs@6.0.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ=="],
121
+
122
+ "babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.6", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-v3P1MW46Lm7VMpAkq0QfyzLWWkC8fh+0aE5Km4msIgDx5kjenHU0pF2s+4/NH8CQn/kla6+Hvws+2AF7bfV5qQ=="],
123
+
124
+ "babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="],
125
+
126
+ "baseline-browser-mapping": ["baseline-browser-mapping@2.10.12", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ=="],
127
+
128
+ "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
129
+
130
+ "bun-plugin-solid": ["bun-plugin-solid@1.0.0", "", { "dependencies": { "@babel/core": ">=7.0.0", "@babel/preset-typescript": ">=7.0.0", "babel-preset-solid": ">=1.8.0" } }, "sha512-H4ZcW4afCLYLDtBsog5cvCfQo8f5E7SD8AeT1woVmIKBOMguy/ml9f1jz9UlikN/i+VK1bS6GII46ZR2OdhbBQ=="],
131
+
132
+ "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
133
+
134
+ "caniuse-lite": ["caniuse-lite@1.0.30001781", "", {}, "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw=="],
135
+
136
+ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
137
+
138
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
139
+
140
+ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
141
+
142
+ "electron-to-chromium": ["electron-to-chromium@1.5.328", "", {}, "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w=="],
143
+
144
+ "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
145
+
146
+ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
147
+
148
+ "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
149
+
150
+ "gl-matrix": ["gl-matrix@3.4.4", "", {}, "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ=="],
151
+
152
+ "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="],
153
+
154
+ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
155
+
156
+ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
157
+
158
+ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
159
+
160
+ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
161
+
162
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
163
+
164
+ "node-releases": ["node-releases@2.0.36", "", {}, "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA=="],
165
+
166
+ "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
167
+
168
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
169
+
170
+ "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
171
+
172
+ "property-graph": ["property-graph@4.1.0", "", {}, "sha512-AvPcP7XECNWy4LGmFQ77k7un4lSKM4eS29PTvW4ck95uYeLxXPWJM7hLuBqK91FaHqCcgJvIUCuNJjjxKE7VKQ=="],
173
+
174
+ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
175
+
176
+ "seroval": ["seroval@1.5.1", "", {}, "sha512-OwrZRZAfhHww0WEnKHDY8OM0U/Qs8OTfIDWhUD4BLpNJUfXK4cGmjiagGze086m+mhI+V2nD0gfbHEnJjb9STA=="],
177
+
178
+ "seroval-plugins": ["seroval-plugins@1.5.1", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-4FbuZ/TMl02sqv0RTFexu0SP6V+ywaIe5bAWCCEik0fk17BhALgwvUDVF7e3Uvf9pxmwCEJsRPmlkUE6HdzLAw=="],
179
+
180
+ "solid-js": ["solid-js@1.9.12", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-QzKaSJq2/iDrWR1As6MHZQ8fQkdOBf8GReYb7L5iKwMGceg7HxDcaOHk0at66tNgn9U2U7dXo8ZZpLIAmGMzgw=="],
181
+
182
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
183
+
184
+ "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
185
+
186
+ "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
187
+
188
+ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
189
+
190
+ "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="],
191
+ }
192
+ }
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ console.log("Hello via Bun!");
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "aether-engine",
3
+ "version": "1.0.0",
4
+ "main": "src/index.ts",
5
+ "types": "src/index.ts",
6
+ "module": "src/index.ts",
7
+ "type": "module",
8
+ "devDependencies": {
9
+ "@biomejs/biome": "^2.4.10",
10
+ "@types/bun": "latest",
11
+ "@types/gl-matrix": "^3.2.0",
12
+ "@types/pngjs": "^6.0.5",
13
+ "bun-plugin-solid": "^1.0.0",
14
+ "pngjs": "^7.0.0"
15
+ },
16
+ "peerDependencies": {
17
+ "typescript": "^5"
18
+ },
19
+ "dependencies": {
20
+ "@tauri-apps/api": "^2.10.1",
21
+ "@gltf-transform/core": "^4.3.0",
22
+ "gl-matrix": "^3.4.4",
23
+ "solid-js": "^1.9.12"
24
+ }
25
+ }
package/serve.ts ADDED
@@ -0,0 +1,125 @@
1
+ import { join } from "node:path";
2
+ import { serve } from "bun";
3
+ import { SolidPlugin } from "bun-plugin-solid";
4
+
5
+ // Trigger an initial build
6
+ await Bun.build({
7
+ entrypoints: ["./dev/main.tsx"],
8
+ outdir: "./dev/dist",
9
+ plugins: [SolidPlugin()],
10
+ sourcemap: "inline",
11
+ });
12
+
13
+ console.log("Serving at http://localhost:3000");
14
+
15
+ serve({
16
+ port: 3000,
17
+ async fetch(req: Request) {
18
+ const url = new URL(req.url);
19
+
20
+ if (url.pathname === "/__aether_dev/list-sprites" && req.method === "GET") {
21
+ const dirPath = join(process.cwd(), "public/assets/sprites");
22
+ const fs = require("node:fs");
23
+ if (!fs.existsSync(dirPath)) {
24
+ return new Response(JSON.stringify([]), {
25
+ headers: { "Content-Type": "application/json" },
26
+ });
27
+ }
28
+ const files = fs.readdirSync(dirPath);
29
+ const sprites = files
30
+ .filter((f: string) => f.endsWith(".json"))
31
+ .map((f: string) => f.replace(".json", ""));
32
+ return new Response(JSON.stringify(sprites), {
33
+ headers: { "Content-Type": "application/json" },
34
+ });
35
+ }
36
+
37
+ // Integrated DevTools Asset Persistance API (Stripped from production logic)
38
+ if (
39
+ url.pathname === "/__aether_dev/save-sprite-meta" &&
40
+ req.method === "POST"
41
+ ) {
42
+ const data = await req.json();
43
+ const name = data.name || "unnamed_sprite";
44
+ const dirPath = join(process.cwd(), "public/assets/sprites");
45
+ const fs = require("node:fs");
46
+ if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
47
+ await Bun.write(
48
+ join(dirPath, `${name}.json`),
49
+ JSON.stringify(data.metadata, null, 2),
50
+ );
51
+ return new Response(
52
+ JSON.stringify({
53
+ success: true,
54
+ assetPath: `/public/assets/sprites/${name}.json`,
55
+ }),
56
+ { headers: { "Content-Type": "application/json" } },
57
+ );
58
+ }
59
+
60
+ if (url.pathname === "/__aether_dev/save-sprite" && req.method === "POST") {
61
+ const data = await req.json();
62
+ const name = data.name || "unnamed_sprite";
63
+ const base64Data = data.png.replace(/^data:image\/png;base64,/, "");
64
+
65
+ const dirPath = join(process.cwd(), "public/assets/sprites");
66
+ const fs = require("node:fs");
67
+ if (!fs.existsSync(dirPath)) {
68
+ fs.mkdirSync(dirPath, { recursive: true });
69
+ }
70
+
71
+ await Bun.write(
72
+ join(dirPath, `${name}.png`),
73
+ Buffer.from(base64Data, "base64"),
74
+ );
75
+ await Bun.write(
76
+ join(dirPath, `${name}.json`),
77
+ JSON.stringify(data.metadata, null, 2),
78
+ );
79
+
80
+ return new Response(
81
+ JSON.stringify({
82
+ success: true,
83
+ assetPath: `/public/assets/sprites/${name}.png`,
84
+ }),
85
+ { headers: { "Content-Type": "application/json" } },
86
+ );
87
+ }
88
+
89
+ // Static Asset Serving
90
+ if (url.pathname.startsWith("/public/")) {
91
+ const decoded = decodeURIComponent(url.pathname);
92
+ const filePath = join(process.cwd(), decoded);
93
+ const file = Bun.file(filePath);
94
+ const exists = await file.exists();
95
+ console.log(
96
+ `[serve] path: ${url.pathname} -> decoded: ${decoded} -> filePath: ${filePath} -> exists: ${exists}`,
97
+ );
98
+ if (exists) {
99
+ return new Response(file);
100
+ }
101
+ }
102
+
103
+ if (url.pathname === "/") {
104
+ let html = await Bun.file("./dev/index.html").text();
105
+ html = html.replace(
106
+ "<head>",
107
+ `<head>\n <meta name="aether-app-id" content="${process.cwd()}" />`,
108
+ );
109
+ return new Response(html, { headers: { "Content-Type": "text/html" } });
110
+ }
111
+ if (url.pathname === "/dist/main.js") {
112
+ // Rebuild on request for fast dev iteration
113
+ await Bun.build({
114
+ entrypoints: ["./dev/main.tsx"],
115
+ outdir: "./dev/dist",
116
+ plugins: [SolidPlugin()],
117
+ sourcemap: "inline",
118
+ });
119
+ return new Response(Bun.file("./dev/dist/main.js"), {
120
+ headers: { "Content-Type": "application/javascript" },
121
+ });
122
+ }
123
+ return new Response("Not Found", { status: 404 });
124
+ },
125
+ });
@@ -0,0 +1,61 @@
1
+ // biome-ignore lint/complexity/noStaticOnlyClass: Engine architecture uses static manager classes
2
+ export class AudioEngine {
3
+ private static _context: AudioContext | null = null;
4
+ private static _buffers = new Map<string, AudioBuffer>();
5
+
6
+ private static _decoderContext: OfflineAudioContext | null = null;
7
+ public static hasUserInteracted: boolean = false;
8
+ private static _listenersAttached: boolean = false;
9
+
10
+ static attachListeners() {
11
+ if (AudioEngine._listenersAttached) return;
12
+ AudioEngine._listenersAttached = true;
13
+ const resumeAudio = () => {
14
+ AudioEngine.hasUserInteracted = true;
15
+ if (!AudioEngine._context) {
16
+ AudioEngine._context = new (
17
+ window.AudioContext || (window as any).webkitAudioContext
18
+ )();
19
+ }
20
+ if (AudioEngine._context.state === "suspended") {
21
+ AudioEngine._context.resume();
22
+ }
23
+ ["keydown", "mousedown", "touchstart", "pointerdown"].forEach((e) => {
24
+ window.removeEventListener(e, resumeAudio);
25
+ });
26
+ };
27
+ ["keydown", "mousedown", "touchstart", "pointerdown"].forEach((e) => {
28
+ window.addEventListener(e, resumeAudio, { once: true });
29
+ });
30
+ }
31
+
32
+ static get context() {
33
+ AudioEngine.attachListeners();
34
+ if (!AudioEngine._context) {
35
+ // Do not instantiate immediately unless interacted, or if forced
36
+ // Developers won't be able to access context actively until interaction
37
+ }
38
+ return AudioEngine._context;
39
+ }
40
+
41
+ static async load(url: string, name: string) {
42
+ AudioEngine.attachListeners();
43
+ const response = await fetch(url);
44
+ const arrayBuffer = await response.arrayBuffer();
45
+
46
+ if (!AudioEngine._decoderContext) {
47
+ AudioEngine._decoderContext = new (
48
+ window.OfflineAudioContext || (window as any).webkitOfflineAudioContext
49
+ )(1, 1, 44100);
50
+ }
51
+
52
+ const audioBuffer =
53
+ await AudioEngine._decoderContext.decodeAudioData(arrayBuffer);
54
+ AudioEngine._buffers.set(name, audioBuffer);
55
+ return audioBuffer;
56
+ }
57
+
58
+ static getBuffer(name: string): AudioBuffer | undefined {
59
+ return AudioEngine._buffers.get(name);
60
+ }
61
+ }
@@ -0,0 +1,65 @@
1
+ import { GLTFAnimation, GLTFSkin, GLTFNode } from "../utils/GLTFLoader";
2
+ import { mat4, quat, vec3 } from "gl-matrix";
3
+
4
+ export class Animator3D {
5
+ public animations: Map<string, GLTFAnimation> = new Map();
6
+ public currentAnimation: string | null = null;
7
+
8
+ public skins: GLTFSkin[] = [];
9
+ public nodes: GLTFNode[] = [];
10
+
11
+ public time: number = 0;
12
+ public speed: number = 1.0;
13
+ public loop: boolean = true;
14
+ public isPlaying: boolean = true;
15
+
16
+ // Output buffer size: maximum 64 bones * 16 floats per mat4 = 1024 floats
17
+ public jointMatrices: Float32Array = new Float32Array(64 * 16);
18
+ public localTransforms: mat4[] = [];
19
+
20
+ constructor(animations: GLTFAnimation[], skins: GLTFSkin[], nodes: GLTFNode[]) {
21
+ for (const anim of animations) {
22
+ this.animations.set(anim.name, anim);
23
+ }
24
+
25
+ if (animations.length > 0) {
26
+ this.currentAnimation = animations[0].name;
27
+ }
28
+
29
+ // Deep clone nodes and skins so each instance can animate independently
30
+ // In a production engine, you'd want to share the base skeleton and only unique the local transforms
31
+ this.nodes = nodes.map(n => ({
32
+ ...n,
33
+ translation: vec3.clone(n.translation),
34
+ rotation: quat.clone(n.rotation),
35
+ scale: vec3.clone(n.scale),
36
+ globalMatrix: mat4.clone(n.globalMatrix)
37
+ }));
38
+
39
+ this.skins = skins;
40
+
41
+ for(let i=0; i<this.nodes.length; i++) {
42
+ this.localTransforms.push(mat4.create());
43
+ }
44
+
45
+ for(let i=0; i<this.jointMatrices.length; i+=16) {
46
+ mat4.identity(new Float32Array(this.jointMatrices.buffer, i * 4, 16));
47
+ }
48
+ }
49
+
50
+ public play(name: string, loop: boolean = true) {
51
+ if (this.animations.has(name)) {
52
+ this.currentAnimation = name;
53
+ this.time = 0;
54
+ this.loop = loop;
55
+ this.isPlaying = true;
56
+ } else {
57
+ console.warn(`Animation ${name} not found.`);
58
+ }
59
+ }
60
+
61
+ public stop() {
62
+ this.isPlaying = false;
63
+ this.time = 0;
64
+ }
65
+ }
@@ -0,0 +1,26 @@
1
+ export class AudioSource {
2
+ public bufferName: string = "";
3
+ public volume: number = 1.0;
4
+ public loop: boolean = false;
5
+
6
+ // Triggers
7
+ public shouldPlay: boolean = false;
8
+ public isPlaying: boolean = false;
9
+
10
+ // Internal WebAudio states
11
+ public _sourceNode?: AudioBufferSourceNode;
12
+ public _gainNode?: GainNode;
13
+
14
+ constructor(bufferName: string = "", volume: number = 1.0) {
15
+ this.bufferName = bufferName;
16
+ this.volume = volume;
17
+ }
18
+
19
+ play() {
20
+ this.shouldPlay = true;
21
+ }
22
+
23
+ stop() {
24
+ this.shouldPlay = false;
25
+ }
26
+ }
@@ -0,0 +1,25 @@
1
+ import { Color } from "../math/Color";
2
+
3
+ export class BitmapText {
4
+ public _text: string = "";
5
+ public fontId: string;
6
+ public color: Color = Color.White();
7
+
8
+ public isDirty: boolean = true;
9
+
10
+ constructor(text: string, fontId: string) {
11
+ this._text = text;
12
+ this.fontId = fontId;
13
+ }
14
+
15
+ get text(): string {
16
+ return this._text;
17
+ }
18
+
19
+ set text(value: string) {
20
+ if (this._text !== value) {
21
+ this._text = value;
22
+ this.isDirty = true;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,33 @@
1
+ import { mat4 } from "gl-matrix";
2
+
3
+ export class Camera {
4
+ public projectionMatrix: mat4 = mat4.create();
5
+ public viewMatrix: mat4 = mat4.create();
6
+ public isOrthographic: boolean = false;
7
+
8
+ // Perspective properties
9
+ public fov: number = (45 * Math.PI) / 180;
10
+ public aspect: number = 1.0;
11
+ public near: number = 0.1;
12
+ public far: number = 1000.0;
13
+
14
+ // Orthographic properties
15
+ public orthoSize: number = 5;
16
+
17
+ updateProjection(width: number, height: number) {
18
+ this.aspect = width / Math.max(height, 1);
19
+ if (this.isOrthographic) {
20
+ const w = this.orthoSize * this.aspect;
21
+ const h = this.orthoSize;
22
+ mat4.ortho(this.projectionMatrix, -w, w, -h, h, this.near, this.far);
23
+ } else {
24
+ mat4.perspective(
25
+ this.projectionMatrix,
26
+ this.fov,
27
+ this.aspect,
28
+ this.near,
29
+ this.far,
30
+ );
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,5 @@
1
+ export class CameraFollow {
2
+ public targetEntityId: number = -1;
3
+ public offset: [number, number, number] = [0, 10, 10];
4
+ public smoothSpeed: number = 5.0;
5
+ }