dopaminejs 1.1.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 (46) 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/ParticleSystem.js +327 -0
  21. package/src/dopamine/effects/WebGLParticleSystem.js +348 -0
  22. package/src/dopamine/index.js +62 -0
  23. package/src/dopamine/utils/TextureGenerator.js +90 -0
  24. package/src/index.js +34 -62
  25. package/src/interfaces/IAudioSystem.js +58 -0
  26. package/src/interfaces/IParticleSystem.js +51 -0
  27. package/src/interfaces/IPhysicsSystem.js +52 -0
  28. package/src/interfaces/ISystem.js +48 -0
  29. package/src/interfaces/index.js +7 -0
  30. package/src/renderer/Renderer.js +37 -0
  31. package/src/systems/Director.js +27 -0
  32. package/src/systems/Input.js +77 -0
  33. package/src/systems/Loader.js +44 -0
  34. package/src/systems/Physics.js +117 -0
  35. package/src/systems/Ticker.js +61 -0
  36. package/ARCHITECTURE.md +0 -71
  37. package/CHANGELOG.md +0 -27
  38. package/README.md +0 -213
  39. package/dist/dopamine.mjs +0 -724
  40. package/dist/dopamine.umd.js +0 -45
  41. package/src/effects/ParticleSystem.js +0 -257
  42. /package/src/{core → dopamine/core}/DataService.js +0 -0
  43. /package/src/{core → dopamine/core}/EventEmitter.js +0 -0
  44. /package/src/{core → dopamine/core}/RewardSystem.js +0 -0
  45. /package/src/{ui → dopamine/ui}/GameUI.js +0 -0
  46. /package/src/{ui → dopamine/ui}/dopamine.css +0 -0
@@ -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
+ };
@@ -0,0 +1,51 @@
1
+ import { ISystem } from './ISystem.js';
2
+
3
+ /**
4
+ * IParticleSystem - Interface for particle system implementations
5
+ *
6
+ * Allows different renderers (Canvas, WebGL, custom) to be swapped
7
+ */
8
+ export const IParticleSystem = {
9
+ ...ISystem,
10
+
11
+ /**
12
+ * Register a sprite for particles
13
+ * @param {string} key - Sprite identifier
14
+ * @param {string} url - Path to image
15
+ */
16
+ registerSprite(key, url) { },
17
+
18
+ /**
19
+ * Register a custom effect
20
+ * @param {string} name - Effect name
21
+ * @param {Function} callback - Effect function (x, y, ...args) => void
22
+ */
23
+ registerEffect(name, callback) { },
24
+
25
+ /**
26
+ * Play a registered effect
27
+ * @param {string} name - Effect name
28
+ * @param {number} x - X position
29
+ * @param {number} y - Y position
30
+ * @param {...any} args - Additional arguments
31
+ */
32
+ play(name, x, y, ...args) { },
33
+
34
+ /**
35
+ * Emit particles with custom configuration
36
+ * @param {Object} config - Particle configuration
37
+ */
38
+ emit(config) { },
39
+
40
+ /**
41
+ * Clear all particles
42
+ */
43
+ clear() { },
44
+
45
+ // Built-in effects (optional, but recommended)
46
+ confetti(x, y, count) { },
47
+ coinShower(x, y, count) { },
48
+ sparkle(x, y, count, color) { },
49
+ fire(x, y, count) { },
50
+ starBurst(x, y, count) { },
51
+ };
@@ -0,0 +1,52 @@
1
+ import { ISystem } from './ISystem.js';
2
+
3
+ /**
4
+ * IPhysicsSystem - Interface for physics implementations
5
+ *
6
+ * Allows different physics engines (custom, Matter.js, Box2D) to be swapped
7
+ */
8
+ export const IPhysicsSystem = {
9
+ ...ISystem,
10
+
11
+ /**
12
+ * Add a physics body to the simulation
13
+ * @param {Object} body - Physics body (implementation-specific)
14
+ */
15
+ addBody(body) { },
16
+
17
+ /**
18
+ * Remove a physics body from the simulation
19
+ * @param {Object} body - Physics body to remove
20
+ */
21
+ removeBody(body) { },
22
+
23
+ /**
24
+ * Check collision between two bodies
25
+ * @param {Object} a - First body
26
+ * @param {Object} b - Second body
27
+ * @returns {boolean} - True if colliding
28
+ */
29
+ checkCollision(a, b) { },
30
+
31
+ /**
32
+ * Perform a raycast
33
+ * @param {Object} origin - Ray origin {x, y}
34
+ * @param {Object} direction - Ray direction {x, y}
35
+ * @param {number} distance - Maximum ray distance
36
+ * @returns {Object|null} - Hit result or null
37
+ */
38
+ raycast(origin, direction, distance) { },
39
+
40
+ /**
41
+ * Set gravity for the physics world
42
+ * @param {number} x - Gravity X component
43
+ * @param {number} y - Gravity Y component
44
+ */
45
+ setGravity(x, y) { },
46
+
47
+ /**
48
+ * Step the physics simulation
49
+ * @param {number} dt - Delta time
50
+ */
51
+ step(dt) { },
52
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * ISystem - Base interface for all systems
3
+ *
4
+ * All systems should implement this interface.
5
+ * Methods are optional - only implement what you need.
6
+ */
7
+ export const ISystem = {
8
+ /**
9
+ * Called when system is registered to the kernel
10
+ * @param {DopamineKernel} kernel - The kernel instance
11
+ */
12
+ init(kernel) { },
13
+
14
+ /**
15
+ * Called each frame (variable timestep)
16
+ * @param {number} dt - Delta time in seconds
17
+ */
18
+ update(dt) { },
19
+
20
+ /**
21
+ * Called at fixed timestep (for physics)
22
+ * @param {number} dt - Fixed delta time
23
+ */
24
+ fixedUpdate(dt) { },
25
+
26
+ /**
27
+ * Called when system is unregistered
28
+ */
29
+ destroy() { },
30
+ };
31
+
32
+ /**
33
+ * Base System class that implements ISystem
34
+ * Systems can extend this for convenience
35
+ */
36
+ export class System {
37
+ constructor() {
38
+ this.kernel = null;
39
+ }
40
+
41
+ init(kernel) {
42
+ this.kernel = kernel;
43
+ }
44
+
45
+ update(dt) { }
46
+ fixedUpdate(dt) { }
47
+ destroy() { }
48
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Export all system interfaces
3
+ */
4
+ export { ISystem, System } from './ISystem.js';
5
+ export { IPhysicsSystem } from './IPhysicsSystem.js';
6
+ export { IAudioSystem } from './IAudioSystem.js';
7
+ export { IParticleSystem } from './IParticleSystem.js';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Handles the Canvas and Context for rendering.
3
+ */
4
+ export class Renderer {
5
+ constructor(options = {}) {
6
+ this.width = options.width || 800;
7
+ this.height = options.height || 600;
8
+ this.backgroundColor = options.backgroundColor || '#000000';
9
+
10
+ this.canvas = document.createElement('canvas');
11
+ this.canvas.width = this.width;
12
+ this.canvas.height = this.height;
13
+ this.ctx = this.canvas.getContext('2d');
14
+
15
+ // Append to body or specified container
16
+ const parent = options.parent ?
17
+ (typeof options.parent === 'string' ? document.querySelector(options.parent) : options.parent)
18
+ : document.body;
19
+
20
+ parent.appendChild(this.canvas);
21
+ }
22
+
23
+ /**
24
+ * Clear the canvas.
25
+ */
26
+ clear() {
27
+ this.ctx.fillStyle = this.backgroundColor;
28
+ this.ctx.fillRect(0, 0, this.width, this.height);
29
+ }
30
+
31
+ resize(width, height) {
32
+ this.width = width;
33
+ this.height = height;
34
+ this.canvas.width = width;
35
+ this.canvas.height = height;
36
+ }
37
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Manages Scene transitions and state.
3
+ */
4
+ export class Director {
5
+ constructor(game) {
6
+ this.game = game;
7
+ this.currentScene = null;
8
+ }
9
+
10
+ /**
11
+ * Switch to a new scene.
12
+ * @param {Scene} scene
13
+ */
14
+ run(scene) {
15
+ if (this.currentScene) {
16
+ this.currentScene.onExit();
17
+ }
18
+
19
+ this.currentScene = scene;
20
+ this.currentScene.game = this.game;
21
+
22
+ // Let the game know (if game engine needs to reference it directly)
23
+ this.game.scene = scene;
24
+
25
+ scene.onEnter();
26
+ }
27
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Input System
3
+ * Tracks keyboard and mouse input.
4
+ */
5
+ export class Input {
6
+ constructor() {
7
+ this.keys = new Map();
8
+ this.mouse = { x: 0, y: 0, buttons: new Map() };
9
+ this.kernel = null;
10
+
11
+ // Bind event listeners
12
+ this._onKeyDown = this._onKeyDown.bind(this);
13
+ this._onKeyUp = this._onKeyUp.bind(this);
14
+ this._onMouseMove = this._onMouseMove.bind(this);
15
+ this._onMouseDown = this._onMouseDown.bind(this);
16
+ this._onMouseUp = this._onMouseUp.bind(this);
17
+ }
18
+
19
+ /**
20
+ * ISystem interface - called when registered
21
+ */
22
+ init(kernel) {
23
+ this.kernel = kernel;
24
+
25
+ // Attach event listeners
26
+ window.addEventListener('keydown', this._onKeyDown);
27
+ window.addEventListener('keyup', this._onKeyUp);
28
+ window.addEventListener('mousemove', this._onMouseMove);
29
+ window.addEventListener('mousedown', this._onMouseDown);
30
+ window.addEventListener('mouseup', this._onMouseUp);
31
+ }
32
+
33
+ /**
34
+ * ISystem interface - cleanup
35
+ */
36
+ destroy() {
37
+ window.removeEventListener('keydown', this._onKeyDown);
38
+ window.removeEventListener('keyup', this._onKeyUp);
39
+ window.removeEventListener('mousemove', this._onMouseMove);
40
+ window.removeEventListener('mousedown', this._onMouseDown);
41
+ window.removeEventListener('mouseup', this._onMouseUp);
42
+ }
43
+
44
+ _onKeyDown(e) {
45
+ this.keys.set(e.key, true);
46
+ }
47
+
48
+ _onKeyUp(e) {
49
+ this.keys.set(e.key, false);
50
+ }
51
+
52
+ _onMouseMove(e) {
53
+ this.mouse.x = e.clientX;
54
+ this.mouse.y = e.clientY;
55
+ }
56
+
57
+ _onMouseDown(e) {
58
+ this.mouse.buttons.set(e.button, true);
59
+ }
60
+
61
+ _onMouseUp(e) {
62
+ this.mouse.buttons.set(e.button, false);
63
+ }
64
+
65
+ isKeyDown(key) {
66
+ return this.keys.get(key) || false;
67
+ }
68
+
69
+ isMouseButtonDown(button = 0) {
70
+ return this.mouse.buttons.get(button) || false;
71
+ }
72
+ }
73
+
74
+ // DEPRECATED: Keep for backward compatibility
75
+ export const GlobalInput = new Input();
76
+ // Note: GlobalInput won't have listeners attached unless init() is called
77
+ console.warn('[DopamineJS] GlobalInput is deprecated. Use kernel.input instead.');
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Asset Loader
3
+ * Loads and caches images, audio, etc.
4
+ */
5
+ export class Loader {
6
+ constructor() {
7
+ this.assets = new Map();
8
+ this.kernel = null;
9
+ }
10
+
11
+ /**
12
+ * ISystem interface - called when registered
13
+ */
14
+ init(kernel) {
15
+ this.kernel = kernel;
16
+ }
17
+
18
+ /**
19
+ * ISystem interface - cleanup
20
+ */
21
+ destroy() {
22
+ this.assets.clear();
23
+ }
24
+
25
+ async loadImage(key, url) {
26
+ return new Promise((resolve, reject) => {
27
+ const img = new Image();
28
+ img.onload = () => {
29
+ this.assets.set(key, img);
30
+ resolve(img);
31
+ };
32
+ img.onerror = reject;
33
+ img.src = url;
34
+ });
35
+ }
36
+
37
+ get(key) {
38
+ return this.assets.get(key);
39
+ }
40
+ }
41
+
42
+ // DEPRECATED: Keep for backward compatibility
43
+ export const GlobalLoader = new Loader();
44
+ console.warn('[DopamineJS] GlobalLoader is deprecated. Use kernel.loader instead.');