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,250 @@
1
+ import { Index, onCleanup, onMount, Show } from "solid-js";
2
+ import {
3
+ draggedItem,
4
+ dragHoverTarget,
5
+ getInvAccessor,
6
+ handleDrop,
7
+ hotbarSlots,
8
+ type InventorySource,
9
+ type Item,
10
+ isDropHandled,
11
+ notifyEquipmentChange,
12
+ selectedHotbarIndex,
13
+ setDraggedItem,
14
+ setDragHoverTarget,
15
+ setHotbarIndex,
16
+ setInvAccessor,
17
+ setIsDropHandled,
18
+ } from "./GameState";
19
+
20
+ export function PlayerHUD() {
21
+ onMount(() => {
22
+ const handleKeyDown = (e: KeyboardEvent) => {
23
+ // Numbers 1-5
24
+ if (e.key >= "1" && e.key <= "5") {
25
+ const index = parseInt(e.key, 10) - 1;
26
+ setHotbarIndex(index);
27
+ }
28
+ };
29
+ window.addEventListener("keydown", handleKeyDown);
30
+ onCleanup(() => {
31
+ window.removeEventListener("keydown", handleKeyDown);
32
+ });
33
+ });
34
+
35
+ const handleDragStart = (
36
+ e: DragEvent,
37
+ source: InventorySource,
38
+ index: number,
39
+ ) => {
40
+ setDraggedItem({ source, index });
41
+ if (e.dataTransfer) {
42
+ e.dataTransfer.effectAllowed = "move";
43
+ e.dataTransfer.setData("text/plain", "");
44
+ }
45
+ };
46
+
47
+ const handleDragOver = (e: DragEvent) => {
48
+ e.preventDefault();
49
+ if (e.dataTransfer) {
50
+ e.dataTransfer.dropEffect = "move";
51
+ }
52
+ };
53
+
54
+ const onDropHandler = (
55
+ e: DragEvent,
56
+ targetSource: InventorySource,
57
+ targetIndex: number,
58
+ ) => {
59
+ e.preventDefault();
60
+ handleDrop(targetSource, targetIndex);
61
+ };
62
+
63
+ const handleDragEnter = (
64
+ e: DragEvent,
65
+ source: InventorySource,
66
+ index: number,
67
+ ) => {
68
+ e.preventDefault();
69
+ setDragHoverTarget({ source, index });
70
+ };
71
+
72
+ const handleDragLeave = (
73
+ _e: DragEvent,
74
+ source: InventorySource,
75
+ index: number,
76
+ ) => {
77
+ const currentTarget = dragHoverTarget();
78
+ if (
79
+ currentTarget &&
80
+ currentTarget.source === source &&
81
+ currentTarget.index === index
82
+ ) {
83
+ setDragHoverTarget(null);
84
+ }
85
+ };
86
+
87
+ const handleDragEnd = (_e: DragEvent) => {
88
+ if (!isDropHandled() && draggedItem()) {
89
+ // Dropped on ground
90
+ const itemInfo = draggedItem()!;
91
+ const invAccess = getInvAccessor(itemInfo.source)();
92
+ const item = invAccess[itemInfo.index];
93
+ if (item) {
94
+ window.dispatchEvent(
95
+ new CustomEvent("DropItemOnGround", { detail: { item } }),
96
+ );
97
+ const newInv = [...invAccess];
98
+ newInv[itemInfo.index] = null;
99
+ setInvAccessor(itemInfo.source, newInv);
100
+ if (itemInfo.source === "hotbar") {
101
+ notifyEquipmentChange();
102
+ }
103
+ }
104
+ }
105
+ setDraggedItem(null);
106
+ setDragHoverTarget(null);
107
+ setIsDropHandled(false);
108
+ };
109
+
110
+ const renderSlot = (
111
+ itemAccessor: () => Item | null,
112
+ source: InventorySource,
113
+ index: number,
114
+ ) => {
115
+ const isSelected = () => selectedHotbarIndex() === index;
116
+
117
+ return (
118
+ <div
119
+ onClick={() => setHotbarIndex(index)}
120
+ style={{
121
+ width: "56px",
122
+ height: "56px",
123
+ background:
124
+ dragHoverTarget()?.source === source &&
125
+ dragHoverTarget()?.index === index &&
126
+ !(
127
+ draggedItem()?.source === source && draggedItem()?.index === index
128
+ )
129
+ ? "rgba(255, 255, 255, 0.2)"
130
+ : "rgba(0, 0, 0, 0.4)",
131
+ border: isSelected()
132
+ ? "3px solid #FFD700"
133
+ : dragHoverTarget()?.source === source &&
134
+ dragHoverTarget()?.index === index &&
135
+ !(
136
+ draggedItem()?.source === source &&
137
+ draggedItem()?.index === index
138
+ )
139
+ ? "1px solid rgba(255, 255, 255, 0.8)"
140
+ : "2px solid rgba(255, 255, 255, 0.2)",
141
+ "border-radius": "8px",
142
+ position: "relative",
143
+ display: "flex",
144
+ "justify-content": "center",
145
+ "align-items": "center",
146
+ cursor: "pointer",
147
+ "box-shadow":
148
+ "inset 0px 2px 4px rgba(0,0,0,0.5), 0 4px 6px rgba(0,0,0,0.3)",
149
+ opacity:
150
+ draggedItem()?.source === source && draggedItem()?.index === index
151
+ ? 0.3
152
+ : 1,
153
+ transition: "all 0.1s ease-in-out",
154
+ "margin-top": isSelected() ? "-10px" : "0px",
155
+ "pointer-events": "auto",
156
+ }}
157
+ draggable={!!itemAccessor()}
158
+ onDragStart={(e) => itemAccessor() && handleDragStart(e, source, index)}
159
+ onDragOver={handleDragOver}
160
+ onDragEnter={(e) => handleDragEnter(e, source, index)}
161
+ onDragLeave={(e) => handleDragLeave(e, source, index)}
162
+ onDrop={(e) => onDropHandler(e, source, index)}
163
+ onDragEnd={handleDragEnd}
164
+ >
165
+ <div
166
+ style={{
167
+ position: "absolute",
168
+ top: "2px",
169
+ left: "4px",
170
+ "font-size": "10px",
171
+ color: "rgba(255,255,255,0.5)",
172
+ "pointer-events": "none",
173
+ }}
174
+ >
175
+ {index + 1}
176
+ </div>
177
+
178
+ <Show when={itemAccessor()}>
179
+ {(it) => {
180
+ const item = () => it();
181
+ return (
182
+ <>
183
+ <Show
184
+ when={item().iconX !== undefined}
185
+ fallback={
186
+ <img
187
+ src={item().icon}
188
+ style={{
189
+ "max-width": "40px",
190
+ "max-height": "40px",
191
+ "object-fit": "contain",
192
+ "pointer-events": "none",
193
+ }}
194
+ />
195
+ }
196
+ >
197
+ <div
198
+ style={{
199
+ width: "40px",
200
+ height: "40px",
201
+ "background-image": `url(${item().icon})`,
202
+ "background-position": `-${item().iconX! * (40 / item().iconW!)}px -${item().iconY! * (40 / item().iconH!)}px`,
203
+ "background-size": `${item().atlasW! * (40 / item().iconW!)}px ${item().atlasH! * (40 / item().iconH!)}px`,
204
+ "pointer-events": "none",
205
+ "image-rendering": "pixelated",
206
+ }}
207
+ ></div>
208
+ </Show>
209
+ <div
210
+ style={{
211
+ position: "absolute",
212
+ bottom: "2px",
213
+ right: "4px",
214
+ "font-size": "12px",
215
+ color: "white",
216
+ "font-weight": "bold",
217
+ "text-shadow": "1px 1px 0px black",
218
+ "pointer-events": "none",
219
+ }}
220
+ >
221
+ {item().quantity > 1 ? item().quantity : ""}
222
+ </div>
223
+ </>
224
+ );
225
+ }}
226
+ </Show>
227
+ </div>
228
+ );
229
+ };
230
+
231
+ return (
232
+ <div
233
+ style={{
234
+ position: "absolute",
235
+ bottom: "30px",
236
+ left: "50%",
237
+ transform: "translateX(-50%)",
238
+ display: "flex",
239
+ gap: "10px",
240
+ "z-index": 5001,
241
+ "user-select": "none",
242
+ "pointer-events": "none",
243
+ }}
244
+ >
245
+ <Index each={hotbarSlots()}>
246
+ {(item, i) => renderSlot(item, "hotbar", i)}
247
+ </Index>
248
+ </div>
249
+ );
250
+ }