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
@@ -0,0 +1,100 @@
1
+ import { vec4 } from "gl-matrix";
2
+
3
+ export class Color {
4
+ public raw: vec4;
5
+
6
+ constructor(
7
+ r: number = 255,
8
+ g: number = 255,
9
+ b: number = 255,
10
+ a: number = 255,
11
+ ) {
12
+ this.raw = vec4.fromValues(r / 255, g / 255, b / 255, a / 255);
13
+ }
14
+
15
+ get r() {
16
+ return this.raw[0] * 255;
17
+ }
18
+ set r(v) {
19
+ this.raw[0] = v / 255;
20
+ }
21
+
22
+ get g() {
23
+ return this.raw[1] * 255;
24
+ }
25
+ set g(v) {
26
+ this.raw[1] = v / 255;
27
+ }
28
+
29
+ get b() {
30
+ return this.raw[2] * 255;
31
+ }
32
+ set b(v) {
33
+ this.raw[2] = v / 255;
34
+ }
35
+
36
+ get a() {
37
+ return this.raw[3] * 255;
38
+ }
39
+ set a(v) {
40
+ this.raw[3] = v / 255;
41
+ }
42
+
43
+ get rNorm() {
44
+ return this.raw[0];
45
+ }
46
+ get gNorm() {
47
+ return this.raw[1];
48
+ }
49
+ get bNorm() {
50
+ return this.raw[2];
51
+ }
52
+ get aNorm() {
53
+ return this.raw[3];
54
+ }
55
+
56
+ set(r: number, g: number, b: number, a: number = 255): this {
57
+ vec4.set(this.raw, r / 255, g / 255, b / 255, a / 255);
58
+ return this;
59
+ }
60
+
61
+ clone(): Color {
62
+ return new Color(this.r, this.g, this.b, this.a);
63
+ }
64
+
65
+ static Red() {
66
+ return new Color(255, 0, 0, 255);
67
+ }
68
+ static Green() {
69
+ return new Color(0, 255, 0, 255);
70
+ }
71
+ static Blue() {
72
+ return new Color(0, 0, 255, 255);
73
+ }
74
+ static White() {
75
+ return new Color(255, 255, 255, 255);
76
+ }
77
+ static Black() {
78
+ return new Color(0, 0, 0, 255);
79
+ }
80
+ static Transparent() {
81
+ return new Color(0, 0, 0, 0);
82
+ }
83
+
84
+ static fromHex(hex: string): Color {
85
+ let h = hex.replace("#", "");
86
+ if (h.length === 3)
87
+ h = h
88
+ .split("")
89
+ .map((c) => c + c)
90
+ .join("");
91
+ if (h.length === 6) h += "FF";
92
+ const val = parseInt(h, 16);
93
+ return new Color(
94
+ (val >> 24) & 255,
95
+ (val >> 16) & 255,
96
+ (val >> 8) & 255,
97
+ val & 255,
98
+ );
99
+ }
100
+ }
@@ -0,0 +1,96 @@
1
+ import { vec2 } from "gl-matrix";
2
+
3
+ export class Vector2 {
4
+ public raw: vec2;
5
+
6
+ private static _pool: Vector2[] = [];
7
+
8
+ public static obtain(x: number = 0, y: number = 0): Vector2 {
9
+ if (Vector2._pool.length > 0) {
10
+ return Vector2._pool.pop()?.set(x, y);
11
+ }
12
+ return new Vector2(x, y);
13
+ }
14
+
15
+ public free() {
16
+ Vector2._pool.push(this);
17
+ }
18
+
19
+ constructor(x: number = 0, y: number = 0) {
20
+ this.raw = vec2.fromValues(x, y);
21
+ }
22
+
23
+ get x() {
24
+ return this.raw[0];
25
+ }
26
+ set x(v) {
27
+ this.raw[0] = v;
28
+ }
29
+
30
+ get y() {
31
+ return this.raw[1];
32
+ }
33
+ set y(v) {
34
+ this.raw[1] = v;
35
+ }
36
+
37
+ set(x: number, y: number): this {
38
+ vec2.set(this.raw, x, y);
39
+ return this;
40
+ }
41
+
42
+ copy(other: Vector2): this {
43
+ vec2.copy(this.raw, other.raw);
44
+ return this;
45
+ }
46
+
47
+ add(other: Vector2): this {
48
+ vec2.add(this.raw, this.raw, other.raw);
49
+ return this;
50
+ }
51
+
52
+ sub(other: Vector2): this {
53
+ vec2.sub(this.raw, this.raw, other.raw);
54
+ return this;
55
+ }
56
+
57
+ multiply(other: Vector2): this {
58
+ vec2.multiply(this.raw, this.raw, other.raw);
59
+ return this;
60
+ }
61
+
62
+ divide(other: Vector2): this {
63
+ vec2.divide(this.raw, this.raw, other.raw);
64
+ return this;
65
+ }
66
+
67
+ scale(scalar: number): this {
68
+ vec2.scale(this.raw, this.raw, scalar);
69
+ return this;
70
+ }
71
+
72
+ distance(other: Vector2): number {
73
+ return vec2.dist(this.raw, other.raw);
74
+ }
75
+
76
+ magnitude(): number {
77
+ return vec2.length(this.raw);
78
+ }
79
+
80
+ length(): number {
81
+ return vec2.length(this.raw);
82
+ }
83
+
84
+ normalize(): this {
85
+ vec2.normalize(this.raw, this.raw);
86
+ return this;
87
+ }
88
+
89
+ clone(): Vector2 {
90
+ return new Vector2(this.x, this.y);
91
+ }
92
+
93
+ static Zero(): Vector2 {
94
+ return new Vector2(0, 0);
95
+ }
96
+ }
@@ -0,0 +1,103 @@
1
+ import { vec3 } from "gl-matrix";
2
+
3
+ export class Vector3 {
4
+ public raw: vec3;
5
+
6
+ private static _pool: Vector3[] = [];
7
+
8
+ public static obtain(x: number = 0, y: number = 0, z: number = 0): Vector3 {
9
+ if (Vector3._pool.length > 0) {
10
+ return Vector3._pool.pop()?.set(x, y, z);
11
+ }
12
+ return new Vector3(x, y, z);
13
+ }
14
+
15
+ public free() {
16
+ Vector3._pool.push(this);
17
+ }
18
+
19
+ constructor(x: number = 0, y: number = 0, z: number = 0) {
20
+ this.raw = vec3.fromValues(x, y, z);
21
+ }
22
+
23
+ get x() {
24
+ return this.raw[0];
25
+ }
26
+ set x(v) {
27
+ this.raw[0] = v;
28
+ }
29
+
30
+ get y() {
31
+ return this.raw[1];
32
+ }
33
+ set y(v) {
34
+ this.raw[1] = v;
35
+ }
36
+
37
+ get z() {
38
+ return this.raw[2];
39
+ }
40
+ set z(v) {
41
+ this.raw[2] = v;
42
+ }
43
+
44
+ set(x: number, y: number, z: number): this {
45
+ vec3.set(this.raw, x, y, z);
46
+ return this;
47
+ }
48
+
49
+ copy(other: Vector3): this {
50
+ vec3.copy(this.raw, other.raw);
51
+ return this;
52
+ }
53
+
54
+ add(other: Vector3): this {
55
+ vec3.add(this.raw, this.raw, other.raw);
56
+ return this;
57
+ }
58
+
59
+ sub(other: Vector3): this {
60
+ vec3.sub(this.raw, this.raw, other.raw);
61
+ return this;
62
+ }
63
+
64
+ multiply(other: Vector3): this {
65
+ vec3.multiply(this.raw, this.raw, other.raw);
66
+ return this;
67
+ }
68
+
69
+ divide(other: Vector3): this {
70
+ vec3.divide(this.raw, this.raw, other.raw);
71
+ return this;
72
+ }
73
+
74
+ scale(scalar: number): this {
75
+ vec3.scale(this.raw, this.raw, scalar);
76
+ return this;
77
+ }
78
+
79
+ distance(other: Vector3): number {
80
+ return vec3.dist(this.raw, other.raw);
81
+ }
82
+
83
+ magnitude(): number {
84
+ return vec3.length(this.raw);
85
+ }
86
+
87
+ length(): number {
88
+ return vec3.length(this.raw);
89
+ }
90
+
91
+ normalize(): this {
92
+ vec3.normalize(this.raw, this.raw);
93
+ return this;
94
+ }
95
+
96
+ clone(): Vector3 {
97
+ return new Vector3(this.x, this.y, this.z);
98
+ }
99
+
100
+ static Zero(): Vector3 {
101
+ return new Vector3(0, 0, 0);
102
+ }
103
+ }
@@ -0,0 +1,168 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Color } from "./Color";
3
+ import { Vector2 } from "./Vector2";
4
+ import { Vector3 } from "./Vector3";
5
+
6
+ describe("Math API", () => {
7
+ test("Vector2 object pooling", () => {
8
+ const v1 = Vector2.obtain(10, 20);
9
+ expect(v1.x).toBe(10);
10
+ expect(v1.y).toBe(20);
11
+
12
+ v1.free();
13
+
14
+ const v2 = Vector2.obtain(5, 5);
15
+ expect(v2).toBe(v1); // Should be the same object reference
16
+ expect(v2.x).toBe(5);
17
+ expect(v2.y).toBe(5);
18
+ });
19
+
20
+ test("Vector3 chaining and operations", () => {
21
+ const v = new Vector3(1, 2, 3);
22
+ const result = v.add(new Vector3(1, 1, 1)).scale(2);
23
+
24
+ expect(result).toBe(v); // Chain should return itself
25
+ expect(v.x).toBe(4);
26
+ expect(v.y).toBe(6);
27
+ expect(v.z).toBe(8);
28
+ });
29
+
30
+ test("Color normalization", () => {
31
+ const c = new Color(255, 127.5, 0, 255);
32
+ expect(c.rNorm).toBe(1);
33
+ expect(c.gNorm).toBeCloseTo(0.5);
34
+ expect(c.bNorm).toBe(0);
35
+ expect(c.aNorm).toBe(1);
36
+ });
37
+
38
+ test("Color statics and hex parsing", () => {
39
+ const c1 = Color.White();
40
+ expect(c1.r).toBe(255);
41
+ const c2 = Color.Black();
42
+ expect(c2.r).toBe(0);
43
+
44
+ const c3 = Color.fromHex("#FF00FF");
45
+ expect(c3.r).toBe(255);
46
+ expect(c3.g).toBe(0);
47
+ expect(c3.b).toBe(255);
48
+
49
+ const c4 = Color.fromHex("00ff00ff");
50
+ expect(c4.g).toBe(255);
51
+
52
+ c4.r = 100;
53
+ c4.g = 100;
54
+ c4.b = 100;
55
+ c4.a = 100;
56
+ expect(c4.r).toBeCloseTo(100);
57
+ expect(c4.g).toBeCloseTo(100);
58
+ expect(c4.b).toBeCloseTo(100);
59
+ expect(c4.a).toBeCloseTo(100);
60
+
61
+ c4.set(50, 50, 50, 50);
62
+ expect(c4.r).toBeCloseTo(50);
63
+ });
64
+
65
+ test("Vector2 math operations", () => {
66
+ const v1 = new Vector2(10, 10);
67
+ const v2 = new Vector2(2, 2);
68
+
69
+ v1.add(v2);
70
+ expect(v1.x).toBe(12);
71
+
72
+ v1.sub(v2);
73
+ expect(v1.x).toBe(10);
74
+
75
+ v1.multiply(v2);
76
+ expect(v1.x).toBe(20);
77
+
78
+ v1.divide(v2);
79
+ expect(v1.x).toBe(10);
80
+
81
+ v1.scale(0.5);
82
+ expect(v1.x).toBe(5);
83
+
84
+ const len = v1.length();
85
+ expect(len).toBeCloseTo(Math.sqrt(50));
86
+
87
+ const mag = v1.magnitude();
88
+ expect(mag).toBe(len);
89
+
90
+ v1.normalize();
91
+ expect(v1.x).toBeCloseTo(Math.SQRT1_2);
92
+
93
+ const dist = v1.distance(new Vector2(0, 0));
94
+ expect(dist).toBeCloseTo(1);
95
+
96
+ const clone = v1.clone();
97
+ expect(clone.x).toBe(v1.x);
98
+
99
+ v1.set(100, 100);
100
+ expect(v1.x).toBe(100);
101
+ expect(v1.y).toBe(100);
102
+
103
+ const v3 = new Vector2();
104
+ v3.x = 7;
105
+ v3.y = 8;
106
+ expect(v3.x).toBe(7);
107
+ expect(v3.y).toBe(8);
108
+
109
+ const v4 = new Vector2().copy(v3);
110
+ expect(v4.x).toBe(7);
111
+ });
112
+
113
+ test("Vector3 full math operations", () => {
114
+ const v1 = new Vector3(10, 10, 10);
115
+ const v2 = new Vector3(2, 2, 2);
116
+
117
+ v1.add(v2);
118
+ expect(v1.x).toBe(12);
119
+
120
+ v1.sub(v2);
121
+ expect(v1.x).toBe(10);
122
+
123
+ v1.multiply(v2);
124
+ expect(v1.x).toBe(20);
125
+
126
+ v1.divide(v2);
127
+ expect(v1.x).toBe(10);
128
+
129
+ v1.scale(2);
130
+ expect(v1.x).toBe(20);
131
+
132
+ const len = v1.length();
133
+ expect(len).toBeCloseTo(Math.sqrt(1200));
134
+
135
+ const mag = v1.magnitude();
136
+ expect(mag).toBe(len);
137
+
138
+ v1.normalize();
139
+ expect(v1.x).toBeCloseTo(0.577);
140
+
141
+ expect(v1.distance(new Vector3(0, 0, 0))).toBeCloseTo(1);
142
+
143
+ v1.set(5, 5, 5);
144
+ expect(v1.x).toBe(5);
145
+
146
+ const clone = v1.clone();
147
+ expect(clone.y).toBe(v1.y);
148
+
149
+ const pooled = Vector3.obtain(1, 2, 3);
150
+ expect(pooled.x).toBe(1);
151
+ expect(pooled.y).toBe(2);
152
+ expect(pooled.z).toBe(3);
153
+
154
+ pooled.x = 9;
155
+ pooled.y = 8;
156
+ pooled.z = 7;
157
+ expect(pooled.x).toBe(9);
158
+ expect(pooled.y).toBe(8);
159
+ expect(pooled.z).toBe(7);
160
+
161
+ const copyCat = new Vector3().copy(pooled);
162
+ expect(copyCat.z).toBe(7);
163
+
164
+ pooled.free();
165
+ const p2 = Vector3.obtain(2, 2, 2);
166
+ expect(p2).toBe(pooled);
167
+ });
168
+ });
@@ -0,0 +1,66 @@
1
+ import { Material } from "./Material";
2
+
3
+ export const GLOW_VS = `
4
+ attribute vec4 aVertexPosition;
5
+ attribute vec2 aTextureCoord;
6
+
7
+ uniform mat4 uModelMatrix;
8
+ uniform mat4 uModelViewMatrix;
9
+ uniform mat4 uProjectionMatrix;
10
+
11
+ varying highp vec2 vTextureCoord;
12
+
13
+ void main(void) {
14
+ gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
15
+ vTextureCoord = aTextureCoord;
16
+ }
17
+ `;
18
+
19
+ export const GLOW_FS = `
20
+ precision mediump float;
21
+
22
+ varying highp vec2 vTextureCoord;
23
+ uniform lowp vec4 uColor;
24
+
25
+ void main(void) {
26
+ // Distance from the center of the quad
27
+ vec2 center = vec2(0.5, 0.5);
28
+ float dist = distance(vTextureCoord, center);
29
+
30
+ // Zelda-like sharp, warm core with a very soft ambient scatter edge
31
+ // CRITICAL: smoothstep(0.5, 0.0) is mathematically UNDEFINED in basic GLSL.
32
+ // Always use edge0 < edge1, and invert algebraically!
33
+ float glow = 1.0 - smoothstep(0.0, 0.5, dist);
34
+
35
+ // Core hot spot for realism (toned down to prevent blinding white center)
36
+ // Avoid pow() completely to bypass catastrophic macOS fractional exp2 driver traps!
37
+ float glow2 = glow * glow;
38
+ float glow4 = glow2 * glow2;
39
+ float hotspot = glow4 * 0.7;
40
+
41
+ // Outer atmospheric scattering (approx glow^2.5)
42
+ float scatter = glow2 * sqrt(glow) * 0.3;
43
+
44
+ float finalAlpha = clamp((hotspot + scatter) * uColor.a, 0.0, 1.0);
45
+
46
+ // Discard completely transparent pixels to absolutely maximize fillrate hardware performance
47
+ if (finalAlpha < 0.01) {
48
+ discard;
49
+ }
50
+
51
+ // Pre-multiply color natively because Screen blending uses (ONE, ONE_MINUS_SRC_COLOR) directly!
52
+ // The GL Fixed Function ALU no longer applies an implicit SRC_ALPHA weight for us.
53
+ gl_FragColor = vec4(uColor.rgb * finalAlpha, finalAlpha);
54
+ }
55
+ `;
56
+
57
+ export class GlowMaterial extends Material {
58
+ constructor() {
59
+ super(GLOW_VS, GLOW_FS);
60
+ // We dynamically use Screen blending to output additive luminosity while inherently securely capping
61
+ // maximum bounds at 1.0, neutralizing aggressive macOS GPU Additive integer wrap artifacts!
62
+ this.blendMode = "Screen";
63
+ this.depthTest = true; // Eclipsed by taller solid things
64
+ this.depthWrite = false; // Soft particles shouldn't interact natively into depth buffer
65
+ }
66
+ }