dopaminejs 1.2.0 → 2.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 (45) hide show
  1. package/dist/dopamine.js +1947 -0
  2. package/dist/dopamine.umd.cjs +45 -0
  3. package/package.json +24 -32
  4. package/src/core/Animator.js +62 -0
  5. package/src/core/Collider.js +50 -0
  6. package/src/core/Component.js +38 -0
  7. package/src/core/DopamineKernel.js +153 -0
  8. package/src/core/EventBus.js +183 -0
  9. package/src/core/Game.js +89 -0
  10. package/src/core/GameObject.js +83 -0
  11. package/src/core/PluginRegistry.js +197 -0
  12. package/src/core/Scene.js +65 -0
  13. package/src/core/Sprite.js +51 -0
  14. package/src/core/SystemRegistry.js +242 -0
  15. package/src/core/Vector2.js +50 -0
  16. package/src/{audio → dopamine/audio}/SoundManager.js +1 -3
  17. package/src/dopamine/components/ParticleEmitter.js +50 -0
  18. package/src/dopamine/components/ScreenShake.js +49 -0
  19. package/src/dopamine/components/index.js +4 -0
  20. package/src/dopamine/effects/WebGLParticleSystem.js +348 -0
  21. package/src/dopamine/index.js +62 -0
  22. package/src/dopamine/utils/TextureGenerator.js +90 -0
  23. package/src/index.js +34 -62
  24. package/src/interfaces/IAudioSystem.js +58 -0
  25. package/src/interfaces/IParticleSystem.js +51 -0
  26. package/src/interfaces/IPhysicsSystem.js +52 -0
  27. package/src/interfaces/ISystem.js +48 -0
  28. package/src/interfaces/index.js +7 -0
  29. package/src/renderer/Renderer.js +37 -0
  30. package/src/systems/Director.js +27 -0
  31. package/src/systems/Input.js +77 -0
  32. package/src/systems/Loader.js +44 -0
  33. package/src/systems/Physics.js +117 -0
  34. package/src/systems/Ticker.js +61 -0
  35. package/ARCHITECTURE.md +0 -71
  36. package/CHANGELOG.md +0 -36
  37. package/README.md +0 -264
  38. package/dist/dopamine.mjs +0 -737
  39. package/dist/dopamine.umd.js +0 -45
  40. /package/src/{core → dopamine/core}/DataService.js +0 -0
  41. /package/src/{core → dopamine/core}/EventEmitter.js +0 -0
  42. /package/src/{core → dopamine/core}/RewardSystem.js +0 -0
  43. /package/src/{effects → dopamine/effects}/ParticleSystem.js +0 -0
  44. /package/src/{ui → dopamine/ui}/GameUI.js +0 -0
  45. /package/src/{ui → dopamine/ui}/dopamine.css +0 -0
@@ -0,0 +1,348 @@
1
+ /**
2
+ * WebGL Particle System
3
+ *
4
+ * High-performance particle renderer using WebGL for 10,000+ particles
5
+ * Implements IParticleSystem interface
6
+ */
7
+
8
+ export class WebGLParticleSystem {
9
+ constructor(config = {}) {
10
+ this.maxParticles = config.maxParticles || 10000;
11
+ this.kernel = null;
12
+
13
+ // WebGL context and resources
14
+ this.canvas = null;
15
+ this.gl = null;
16
+ this.program = null;
17
+ this.particleBuffer = null;
18
+
19
+ // Particle data (flat arrays for GPU upload)
20
+ this.positions = new Float32Array(this.maxParticles * 2); // x, y
21
+ this.velocities = new Float32Array(this.maxParticles * 2); // vx, vy
22
+ this.colors = new Float32Array(this.maxParticles * 4); // r, g, b, a
23
+ this.sizes = new Float32Array(this.maxParticles);
24
+ this.lifetimes = new Float32Array(this.maxParticles);
25
+ this.ages = new Float32Array(this.maxParticles);
26
+
27
+ this.particleCount = 0;
28
+ this.registeredEffects = new Map();
29
+ }
30
+
31
+ // ISystem interface
32
+ init(kernel) {
33
+ this.kernel = kernel;
34
+ this._initWebGL();
35
+ this._createShaders();
36
+ this._createBuffers();
37
+
38
+ console.log('[WebGLParticles] Initialized with max particles:', this.maxParticles);
39
+ }
40
+
41
+ update(dt) {
42
+ // Update particle physics
43
+ for (let i = 0; i < this.particleCount; i++) {
44
+ // Update age
45
+ this.ages[i] += dt;
46
+
47
+ // Remove dead particles
48
+ if (this.ages[i] >= this.lifetimes[i]) {
49
+ this._removeParticle(i);
50
+ i--; // Recheck this index
51
+ continue;
52
+ }
53
+
54
+ // Update position
55
+ this.positions[i * 2] += this.velocities[i * 2] * dt;
56
+ this.positions[i * 2 + 1] += this.velocities[i * 2 + 1] * dt;
57
+
58
+ // Apply gravity
59
+ this.velocities[i * 2 + 1] += 500 * dt; // Gravity
60
+
61
+ // Fade out
62
+ const lifeRatio = this.ages[i] / this.lifetimes[i];
63
+ this.colors[i * 4 + 3] = 1 - lifeRatio; // Alpha fade
64
+ }
65
+
66
+ // Render
67
+ this._render();
68
+ }
69
+
70
+ destroy() {
71
+ if (this.gl) {
72
+ this.gl.deleteProgram(this.program);
73
+ this.gl.deleteBuffer(this.particleBuffer);
74
+ }
75
+ if (this.canvas && this.canvas.parentNode) {
76
+ this.canvas.parentNode.removeChild(this.canvas);
77
+ }
78
+ }
79
+
80
+ // IParticleSystem interface
81
+ registerSprite(key, url) {
82
+ // WebGL particles use point sprites, not textures (for simplicity)
83
+ console.warn('[WebGLParticles] Sprite registration not yet implemented');
84
+ }
85
+
86
+ registerEffect(name, callback) {
87
+ this.registeredEffects.set(name, callback);
88
+ }
89
+
90
+ play(name, x, y, ...args) {
91
+ const effect = this.registeredEffects.get(name);
92
+ if (effect) {
93
+ effect.call(this, x, y, ...args);
94
+ }
95
+ }
96
+
97
+ emit(config) {
98
+ const {
99
+ x = 0,
100
+ y = 0,
101
+ count = 10,
102
+ color = [1, 1, 1, 1],
103
+ size = 5,
104
+ lifetime = 1,
105
+ velocity = { x: 0, y: -100 },
106
+ spread = 50
107
+ } = config;
108
+
109
+ for (let i = 0; i < count; i++) {
110
+ if (this.particleCount >= this.maxParticles) break;
111
+
112
+ const idx = this.particleCount;
113
+
114
+ // Position
115
+ this.positions[idx * 2] = x + (Math.random() - 0.5) * spread;
116
+ this.positions[idx * 2 + 1] = y + (Math.random() - 0.5) * spread;
117
+
118
+ // Velocity
119
+ const angle = Math.random() * Math.PI * 2;
120
+ const speed = Math.random() * 200 + 100;
121
+ this.velocities[idx * 2] = Math.cos(angle) * speed + velocity.x;
122
+ this.velocities[idx * 2 + 1] = Math.sin(angle) * speed + velocity.y;
123
+
124
+ // Color
125
+ this.colors[idx * 4] = color[0];
126
+ this.colors[idx * 4 + 1] = color[1];
127
+ this.colors[idx * 4 + 2] = color[2];
128
+ this.colors[idx * 4 + 3] = color[3];
129
+
130
+ // Size and lifetime
131
+ this.sizes[idx] = size;
132
+ this.lifetimes[idx] = lifetime;
133
+ this.ages[idx] = 0;
134
+
135
+ this.particleCount++;
136
+ }
137
+ }
138
+
139
+ clear() {
140
+ this.particleCount = 0;
141
+ }
142
+
143
+ // Built-in effects
144
+ confetti(x, y, count = 50) {
145
+ const colors = [
146
+ [1, 0, 0, 1], // Red
147
+ [0, 1, 0, 1], // Green
148
+ [0, 0, 1, 1], // Blue
149
+ [1, 1, 0, 1], // Yellow
150
+ [1, 0, 1, 1], // Magenta
151
+ ];
152
+
153
+ for (let i = 0; i < count; i++) {
154
+ this.emit({
155
+ x, y,
156
+ count: 1,
157
+ color: colors[Math.floor(Math.random() * colors.length)],
158
+ size: Math.random() * 8 + 4,
159
+ lifetime: Math.random() * 2 + 1,
160
+ velocity: { x: 0, y: -300 },
161
+ spread: 100
162
+ });
163
+ }
164
+ }
165
+
166
+ sparkle(x, y, count = 20, color = [1, 1, 1, 1]) {
167
+ this.emit({
168
+ x, y,
169
+ count,
170
+ color,
171
+ size: 3,
172
+ lifetime: 0.5,
173
+ velocity: { x: 0, y: -50 },
174
+ spread: 30
175
+ });
176
+ }
177
+
178
+ // Private methods
179
+ _initWebGL() {
180
+ // Create overlay canvas
181
+ this.canvas = document.createElement('canvas');
182
+ this.canvas.style.cssText = `
183
+ position: fixed;
184
+ top: 0;
185
+ left: 0;
186
+ width: 100%;
187
+ height: 100%;
188
+ pointer-events: none;
189
+ z-index: 9999;
190
+ `;
191
+ this.canvas.width = window.innerWidth;
192
+ this.canvas.height = window.innerHeight;
193
+ document.body.appendChild(this.canvas);
194
+
195
+ // Get WebGL context
196
+ this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl');
197
+ if (!this.gl) {
198
+ console.error('[WebGLParticles] WebGL not supported');
199
+ return;
200
+ }
201
+
202
+ // Setup WebGL state
203
+ this.gl.enable(this.gl.BLEND);
204
+ this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
205
+
206
+ // Handle resize
207
+ window.addEventListener('resize', () => {
208
+ this.canvas.width = window.innerWidth;
209
+ this.canvas.height = window.innerHeight;
210
+ this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
211
+ });
212
+ }
213
+
214
+ _createShaders() {
215
+ const vertexShaderSource = `
216
+ attribute vec2 a_position;
217
+ attribute vec4 a_color;
218
+ attribute float a_size;
219
+
220
+ uniform vec2 u_resolution;
221
+
222
+ varying vec4 v_color;
223
+
224
+ void main() {
225
+ // Convert from pixels to clip space
226
+ vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;
227
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
228
+ gl_PointSize = a_size;
229
+ v_color = a_color;
230
+ }
231
+ `;
232
+
233
+ const fragmentShaderSource = `
234
+ precision mediump float;
235
+ varying vec4 v_color;
236
+
237
+ void main() {
238
+ // Circular point sprite
239
+ vec2 coord = gl_PointCoord - vec2(0.5);
240
+ if (length(coord) > 0.5) {
241
+ discard;
242
+ }
243
+ gl_FragColor = v_color;
244
+ }
245
+ `;
246
+
247
+ const vertexShader = this._compileShader(this.gl.VERTEX_SHADER, vertexShaderSource);
248
+ const fragmentShader = this._compileShader(this.gl.FRAGMENT_SHADER, fragmentShaderSource);
249
+
250
+ this.program = this.gl.createProgram();
251
+ this.gl.attachShader(this.program, vertexShader);
252
+ this.gl.attachShader(this.program, fragmentShader);
253
+ this.gl.linkProgram(this.program);
254
+
255
+ if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
256
+ console.error('[WebGLParticles] Shader program failed to link');
257
+ }
258
+ }
259
+
260
+ _compileShader(type, source) {
261
+ const shader = this.gl.createShader(type);
262
+ this.gl.shaderSource(shader, source);
263
+ this.gl.compileShader(shader);
264
+
265
+ if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
266
+ console.error('[WebGLParticles] Shader compilation error:', this.gl.getShaderInfoLog(shader));
267
+ this.gl.deleteShader(shader);
268
+ return null;
269
+ }
270
+
271
+ return shader;
272
+ }
273
+
274
+ _createBuffers() {
275
+ this.particleBuffer = this.gl.createBuffer();
276
+ }
277
+
278
+ _render() {
279
+ const gl = this.gl;
280
+
281
+ // Clear canvas
282
+ gl.clearColor(0, 0, 0, 0);
283
+ gl.clear(gl.COLOR_BUFFER_BIT);
284
+
285
+ if (this.particleCount === 0) return;
286
+
287
+ // Use shader program
288
+ gl.useProgram(this.program);
289
+
290
+ // Set resolution uniform
291
+ const resolutionLocation = gl.getUniformLocation(this.program, 'u_resolution');
292
+ gl.uniform2f(resolutionLocation, this.canvas.width, this.canvas.height);
293
+
294
+ // Interleave particle data for GPU
295
+ const vertexData = new Float32Array(this.particleCount * 7); // x, y, r, g, b, a, size
296
+ for (let i = 0; i < this.particleCount; i++) {
297
+ vertexData[i * 7] = this.positions[i * 2];
298
+ vertexData[i * 7 + 1] = this.positions[i * 2 + 1];
299
+ vertexData[i * 7 + 2] = this.colors[i * 4];
300
+ vertexData[i * 7 + 3] = this.colors[i * 4 + 1];
301
+ vertexData[i * 7 + 4] = this.colors[i * 4 + 2];
302
+ vertexData[i * 7 + 5] = this.colors[i * 4 + 3];
303
+ vertexData[i * 7 + 6] = this.sizes[i];
304
+ }
305
+
306
+ // Upload to GPU
307
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.particleBuffer);
308
+ gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.DYNAMIC_DRAW);
309
+
310
+ // Setup attributes
311
+ const stride = 7 * 4; // 7 floats * 4 bytes
312
+
313
+ const positionLocation = gl.getAttribLocation(this.program, 'a_position');
314
+ gl.enableVertexAttribArray(positionLocation);
315
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, stride, 0);
316
+
317
+ const colorLocation = gl.getAttribLocation(this.program, 'a_color');
318
+ gl.enableVertexAttribArray(colorLocation);
319
+ gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, stride, 2 * 4);
320
+
321
+ const sizeLocation = gl.getAttribLocation(this.program, 'a_size');
322
+ gl.enableVertexAttribArray(sizeLocation);
323
+ gl.vertexAttribPointer(sizeLocation, 1, gl.FLOAT, false, stride, 6 * 4);
324
+
325
+ // Draw particles
326
+ gl.drawArrays(gl.POINTS, 0, this.particleCount);
327
+ }
328
+
329
+ _removeParticle(index) {
330
+ // Swap with last particle and decrease count
331
+ const last = this.particleCount - 1;
332
+ if (index !== last) {
333
+ // Copy last particle to this index
334
+ this.positions[index * 2] = this.positions[last * 2];
335
+ this.positions[index * 2 + 1] = this.positions[last * 2 + 1];
336
+ this.velocities[index * 2] = this.velocities[last * 2];
337
+ this.velocities[index * 2 + 1] = this.velocities[last * 2 + 1];
338
+ this.colors[index * 4] = this.colors[last * 4];
339
+ this.colors[index * 4 + 1] = this.colors[last * 4 + 1];
340
+ this.colors[index * 4 + 2] = this.colors[last * 4 + 2];
341
+ this.colors[index * 4 + 3] = this.colors[last * 4 + 3];
342
+ this.sizes[index] = this.sizes[last];
343
+ this.lifetimes[index] = this.lifetimes[last];
344
+ this.ages[index] = this.ages[last];
345
+ }
346
+ this.particleCount--;
347
+ }
348
+ }
@@ -0,0 +1,62 @@
1
+ import { RewardSystem } from './core/RewardSystem.js';
2
+ import { DataService } from './core/DataService.js';
3
+ import { GameUI } from './ui/GameUI.js';
4
+ import { ParticleSystem } from './effects/ParticleSystem.js';
5
+ import { SoundManager } from './audio/SoundManager.js';
6
+ import './ui/dopamine.css';
7
+
8
+ export { RewardSystem, DataService, GameUI, ParticleSystem, SoundManager };
9
+
10
+ export default class Dopamine {
11
+ constructor(config = {}) {
12
+ this.config = config;
13
+
14
+ // Initialize subsystems with config
15
+ this.dataService = new DataService(config.data || {});
16
+ this.rewardSystem = new RewardSystem(this.dataService, config.rewards || {});
17
+ this.soundManager = new SoundManager(config.sound || {});
18
+ this.particleSystem = new ParticleSystem(config.particles || {});
19
+ this.gameUI = new GameUI(this.particleSystem);
20
+
21
+ // Bind UI to RewardSystem events
22
+ this._bindEvents();
23
+ }
24
+
25
+ async init() {
26
+ await this.rewardSystem.init();
27
+ console.log('DopamineJS Initialized 🚀');
28
+ return {
29
+ rewardSystem: this.rewardSystem,
30
+ gameUI: this.gameUI,
31
+ particleSystem: this.particleSystem,
32
+ soundManager: this.soundManager
33
+ };
34
+ }
35
+
36
+ _bindEvents() {
37
+ this.rewardSystem.on('xp_gained', (data) => {
38
+ const { total, needed } = this.rewardSystem.getXPForNextLevel();
39
+ this.gameUI.updateXP(this.rewardSystem.player.xp, needed, total);
40
+
41
+ if (data.xpGained > 0) {
42
+ // Show floating text for XP gain
43
+ // We might need a way to know WHERE to show this, or just show it in a standard place
44
+ // For now, let's just update the bar
45
+ }
46
+ });
47
+
48
+ this.rewardSystem.on('level_up', (data) => {
49
+ this.gameUI.updateLevel(data.newLevel);
50
+ this.gameUI.showLevelUp(data.oldLevel, data.newLevel);
51
+ });
52
+
53
+ this.rewardSystem.on('achievement_unlocked', (achievement) => {
54
+ this.gameUI.showAchievement(achievement);
55
+ });
56
+
57
+ this.rewardSystem.on('new_high_score', (data) => {
58
+ this.gameUI.showNotification(`New High Score: ${data.score}!`, 'legendary');
59
+ this.soundManager.playSuccess();
60
+ });
61
+ }
62
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Generates procedural textures for prototyping.
3
+ */
4
+ export class TextureGenerator {
5
+ static createGround(width, height, color = '#333') {
6
+ const canvas = document.createElement('canvas');
7
+ canvas.width = width;
8
+ canvas.height = height;
9
+ const ctx = canvas.getContext('2d');
10
+
11
+ ctx.fillStyle = color;
12
+ ctx.fillRect(0, 0, width, height);
13
+
14
+ // Noise / Grit
15
+ for (let i = 0; i < 1000; i++) {
16
+ ctx.fillStyle = Math.random() > 0.5 ? '#444' : '#222';
17
+ const size = Math.random() * 4 + 2;
18
+ ctx.fillRect(Math.random() * width, Math.random() * height, size, size);
19
+ }
20
+
21
+ // Grid lines overlay (faint)
22
+ ctx.strokeStyle = 'rgba(255,255,255,0.05)';
23
+ ctx.lineWidth = 2;
24
+ ctx.beginPath();
25
+ for (let i = 0; i <= width; i += 64) {
26
+ ctx.moveTo(i, 0); ctx.lineTo(i, height);
27
+ }
28
+ for (let i = 0; i <= height; i += 64) {
29
+ ctx.moveTo(0, i); ctx.lineTo(width, i);
30
+ }
31
+ ctx.stroke();
32
+
33
+ return canvas;
34
+ }
35
+
36
+ static createCharacterSheet(colorBody, colorDetail) {
37
+ // Create a 4-frame walk cycle strip (Vertical or Horizontal)
38
+ // Let's do Horizontal: 64x64 frames, 4 frames -> 256x64 image
39
+ const cellW = 64;
40
+ const cellH = 64;
41
+ const canvas = document.createElement('canvas');
42
+ canvas.width = cellW * 4;
43
+ canvas.height = cellH;
44
+ const ctx = canvas.getContext('2d');
45
+
46
+ for (let i = 0; i < 4; i++) {
47
+ const x = i * cellW;
48
+ const y = 0;
49
+ const cx = x + cellW / 2;
50
+ const cy = y + cellH / 2;
51
+
52
+ // -- Frame Animation Variances --
53
+ // Bobbing effect
54
+ const bob = (i % 2 === 0) ? 0 : -2;
55
+ // Leg swing (simulated by shape change or just simple offset)
56
+ const legOffset = (i === 1) ? 5 : (i === 3 ? -5 : 0);
57
+
58
+ // Body
59
+ ctx.fillStyle = colorBody;
60
+ ctx.beginPath();
61
+ ctx.arc(cx, cy + bob, 20, 0, Math.PI * 2);
62
+ ctx.fill();
63
+
64
+ // Shoulders/Hands (Top Down)
65
+ ctx.fillStyle = colorDetail;
66
+ ctx.beginPath();
67
+ ctx.arc(cx - 15, cy + bob + legOffset, 8, 0, Math.PI * 2); // Left hand
68
+ ctx.arc(cx + 15, cy + bob - legOffset, 8, 0, Math.PI * 2); // Right hand
69
+ ctx.fill();
70
+
71
+ // Head/Helmet
72
+ ctx.fillStyle = adjustColor(colorBody, -20);
73
+ ctx.beginPath();
74
+ ctx.arc(cx, cy + bob, 15, 0, Math.PI * 2);
75
+ ctx.fill();
76
+
77
+ // Gun (if soldier)
78
+ if (colorDetail === '#333') { // Hacky check
79
+ ctx.fillStyle = '#000';
80
+ ctx.fillRect(cx + 10, cy + bob - 5, 25, 6);
81
+ }
82
+ }
83
+
84
+ return canvas;
85
+ }
86
+ }
87
+
88
+ function adjustColor(color, amount) {
89
+ return color; // Placeholder for color darkening logic
90
+ }
package/src/index.js CHANGED
@@ -1,62 +1,34 @@
1
- import { RewardSystem } from './core/RewardSystem.js';
2
- import { DataService } from './core/DataService.js';
3
- import { GameUI } from './ui/GameUI.js';
4
- import { ParticleSystem } from './effects/ParticleSystem.js';
5
- import { SoundManager } from './audio/SoundManager.js';
6
- import './ui/dopamine.css';
7
-
8
- export { RewardSystem, DataService, GameUI, ParticleSystem, SoundManager };
9
-
10
- export default class Dopamine {
11
- constructor(config = {}) {
12
- this.config = config;
13
-
14
- // Initialize subsystems with config
15
- this.dataService = new DataService(config.data || {});
16
- this.rewardSystem = new RewardSystem(this.dataService, config.rewards || {});
17
- this.soundManager = new SoundManager(config.sound || {});
18
- this.particleSystem = new ParticleSystem(config.particles || {});
19
- this.gameUI = new GameUI(this.particleSystem);
20
-
21
- // Bind UI to RewardSystem events
22
- this._bindEvents();
23
- }
24
-
25
- async init() {
26
- await this.rewardSystem.init();
27
- console.log('DopamineJS Initialized 🚀');
28
- return {
29
- rewardSystem: this.rewardSystem,
30
- gameUI: this.gameUI,
31
- particleSystem: this.particleSystem,
32
- soundManager: this.soundManager
33
- };
34
- }
35
-
36
- _bindEvents() {
37
- this.rewardSystem.on('xp_gained', (data) => {
38
- const { total, needed } = this.rewardSystem.getXPForNextLevel();
39
- this.gameUI.updateXP(this.rewardSystem.player.xp, needed, total);
40
-
41
- if (data.xpGained > 0) {
42
- // Show floating text for XP gain
43
- // We might need a way to know WHERE to show this, or just show it in a standard place
44
- // For now, let's just update the bar
45
- }
46
- });
47
-
48
- this.rewardSystem.on('level_up', (data) => {
49
- this.gameUI.updateLevel(data.newLevel);
50
- this.gameUI.showLevelUp(data.oldLevel, data.newLevel);
51
- });
52
-
53
- this.rewardSystem.on('achievement_unlocked', (achievement) => {
54
- this.gameUI.showAchievement(achievement);
55
- });
56
-
57
- this.rewardSystem.on('new_high_score', (data) => {
58
- this.gameUI.showNotification(`New High Score: ${data.score}!`, 'legendary');
59
- this.soundManager.playSuccess();
60
- });
61
- }
62
- }
1
+ import Dopamine from './dopamine/index.js';
2
+
3
+ // Re-export legacy systems
4
+ export * from './dopamine/index.js';
5
+
6
+ // Export New Kernel Architecture (Phase 0)
7
+ export { DopamineKernel } from './core/DopamineKernel.js';
8
+ export { EventBus } from './core/EventBus.js';
9
+ export { SystemRegistry } from './core/SystemRegistry.js';
10
+ export { PluginRegistry } from './core/PluginRegistry.js';
11
+
12
+ // Export System Interfaces
13
+ export * from './interfaces/index.js';
14
+
15
+ // Export New Engine Core
16
+ export { Game } from './core/Game.js';
17
+ export { Scene } from './core/Scene.js';
18
+ export { GameObject } from './core/GameObject.js';
19
+ export { Component } from './core/Component.js';
20
+ export { Renderer } from './renderer/Renderer.js';
21
+ export { Ticker } from './systems/Ticker.js';
22
+ export { Loader, GlobalLoader } from './systems/Loader.js';
23
+ export { Input, GlobalInput } from './systems/Input.js';
24
+ export { Director } from './systems/Director.js';
25
+ export { Physics, GlobalPhysics } from './systems/Physics.js';
26
+ export { Vector2 } from './core/Vector2.js';
27
+ export { Collider } from './core/Collider.js';
28
+ export { Sprite } from './core/Sprite.js';
29
+ export { Animator } from './core/Animator.js';
30
+ export { TextureGenerator } from './dopamine/utils/TextureGenerator.js';
31
+ export { ParticleEmitter, ScreenShake } from './dopamine/components/index.js';
32
+
33
+ // Export default for backward compatibility
34
+ export default Dopamine;
@@ -0,0 +1,58 @@
1
+ import { ISystem } from './ISystem.js';
2
+
3
+ /**
4
+ * IAudioSystem - Interface for audio implementations
5
+ *
6
+ * Allows different audio engines (Web Audio, Howler.js, etc.) to be swapped
7
+ */
8
+ export const IAudioSystem = {
9
+ ...ISystem,
10
+
11
+ /**
12
+ * Register a sound with a key
13
+ * @param {string} key - Sound identifier
14
+ * @param {string} url - Path to audio file
15
+ */
16
+ registerSound(key, url) { },
17
+
18
+ /**
19
+ * Preload multiple sounds
20
+ * @param {Object} soundMap - Map of key -> url
21
+ * @returns {Promise<void>}
22
+ */
23
+ preloadSounds(soundMap) { },
24
+
25
+ /**
26
+ * Play a sound by key
27
+ * @param {string} key - Sound identifier
28
+ * @param {Object} options - Playback options (volume, loop, etc.)
29
+ */
30
+ play(key, options) { },
31
+
32
+ /**
33
+ * Play a synthesized tone
34
+ * @param {number} frequency - Frequency in Hz
35
+ * @param {number} duration - Duration in seconds
36
+ * @param {string} type - Waveform type ('sine', 'square', etc.)
37
+ * @param {number} volume - Volume (0-1)
38
+ */
39
+ playTone(frequency, duration, type, volume) { },
40
+
41
+ /**
42
+ * Stop a playing sound
43
+ * @param {string} key - Sound identifier
44
+ */
45
+ stop(key) { },
46
+
47
+ /**
48
+ * Toggle mute state
49
+ * @returns {boolean} - New mute state
50
+ */
51
+ toggleMute() { },
52
+
53
+ /**
54
+ * Set master volume
55
+ * @param {number} volume - Volume (0-1)
56
+ */
57
+ setVolume(volume) { },
58
+ };