dopaminejs 2.0.1 → 2.0.2

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.
package/dist/dopamine.js CHANGED
@@ -280,7 +280,7 @@ class P {
280
280
  this.storage.removeItem(this.prefix + t);
281
281
  }
282
282
  }
283
- class T {
283
+ class C {
284
284
  constructor(t) {
285
285
  this.particleSystem = t, this.container = null, this.xpBar = null, this.levelDisplay = null, this.streakDisplay = null, this.init();
286
286
  }
@@ -430,7 +430,7 @@ class T {
430
430
  `, document.body.appendChild(e);
431
431
  }
432
432
  }
433
- class C {
433
+ class T {
434
434
  constructor(t = {}) {
435
435
  this.container = t.container ? typeof t.container == "string" ? document.querySelector(t.container) : t.container : document.body, this.canvasId = t.canvasId || "dopamine-particle-canvas", this.canvas = document.getElementById(this.canvasId), this.canvas || (this.canvas = document.createElement("canvas"), this.canvas.id = this.canvasId, this.canvas.style.pointerEvents = "none", this.canvas.style.zIndex = t.zIndex || "9999", this.container === document.body ? (this.canvas.style.position = "fixed", this.canvas.style.top = "0", this.canvas.style.left = "0") : (this.canvas.style.position = "absolute", this.canvas.style.top = "0", this.canvas.style.left = "0", window.getComputedStyle(this.container).position === "static" && (this.container.style.position = "relative")), this.container.appendChild(this.canvas)), this.ctx = this.canvas.getContext("2d"), this.particles = [], this.pool = [], this.sprites = /* @__PURE__ */ new Map(), this.customEffects = /* @__PURE__ */ new Map(), this.isAnimating = !1, this._resize(), window.ResizeObserver && this.container !== document.body ? new ResizeObserver(() => this._resize()).observe(this.container) : window.addEventListener("resize", () => this._resize());
436
436
  }
@@ -481,8 +481,8 @@ class C {
481
481
  size: f = 5
482
482
  } = t;
483
483
  for (let v = 0; v < i; v++) {
484
- const l = this._getParticle(), x = m + (Math.random() - 0.5) * u, w = Math.random() * r;
485
- l.x = e, l.y = s, l.vx = Math.cos(x) * w, l.vy = Math.sin(x) * w, l.life = h, l.decay = o * (0.8 + Math.random() * 0.4), l.gravity = n, l.color = Array.isArray(c) ? c[Math.floor(Math.random() * c.length)] : c, l.size = f * (0.8 + Math.random() * 0.4), l.sprite = d, l.rotation = Math.random() * Math.PI * 2, l.rotationSpeed = (Math.random() - 0.5) * 0.2, this.particles.push(l);
484
+ const l = this._getParticle(), w = m + (Math.random() - 0.5) * u, x = Math.random() * r;
485
+ l.x = e, l.y = s, l.vx = Math.cos(w) * x, l.vy = Math.sin(w) * x, l.life = h, l.decay = o * (0.8 + Math.random() * 0.4), l.gravity = n, l.color = Array.isArray(c) ? c[Math.floor(Math.random() * c.length)] : c, l.size = f * (0.8 + Math.random() * 0.4), l.sprite = d, l.rotation = Math.random() * Math.PI * 2, l.rotationSpeed = (Math.random() - 0.5) * 0.2, this.particles.push(l);
486
486
  }
487
487
  this._startAnimation();
488
488
  }
@@ -701,12 +701,12 @@ class I {
701
701
  this.playTone(200, 0.2, "sawtooth", 0.3);
702
702
  }
703
703
  }
704
- class $ {
704
+ class B {
705
705
  constructor(t = {}) {
706
- this.config = t, this.dataService = new P(t.data || {}), this.rewardSystem = new E(this.dataService, t.rewards || {}), this.soundManager = new I(t.sound || {}), this.particleSystem = new C(t.particles || {}), this.gameUI = new T(this.particleSystem), this._bindEvents();
706
+ this.config = t, this.dataService = new P(t.data || {}), this.rewardSystem = new E(this.dataService, t.rewards || {}), this.soundManager = new I(t.sound || {}), this.particleSystem = new T(t.particles || {}), this.gameUI = new C(this.particleSystem), this._bindEvents();
707
707
  }
708
708
  async init() {
709
- return await this.rewardSystem.init(), console.log("DopamineJS Initialized 🚀"), {
709
+ return await this.rewardSystem.init(), {
710
710
  rewardSystem: this.rewardSystem,
711
711
  gameUI: this.gameUI,
712
712
  particleSystem: this.particleSystem,
@@ -979,7 +979,7 @@ class A {
979
979
  t.init(this.kernel), this.kernel.events.emit("plugin_loaded", {
980
980
  name: t.name,
981
981
  version: t.version
982
- }), console.log(`[PluginRegistry] Loaded plugin: ${t.name}${t.version ? ` v${t.version}` : ""}`);
982
+ });
983
983
  } catch (e) {
984
984
  throw console.error(`[PluginRegistry] Failed to initialize plugin "${t.name}":`, e), this._plugins.delete(t.name), this._loadOrder.pop(), e;
985
985
  }
@@ -1004,7 +1004,7 @@ class A {
1004
1004
  await t.init(this.kernel), this.kernel.events.emit("plugin_loaded", {
1005
1005
  name: t.name,
1006
1006
  version: t.version
1007
- }), console.log(`[PluginRegistry] Loaded plugin: ${t.name}${t.version ? ` v${t.version}` : ""}`);
1007
+ });
1008
1008
  } catch (e) {
1009
1009
  throw console.error(`[PluginRegistry] Failed to initialize plugin "${t.name}":`, e), this._plugins.delete(t.name), this._loadOrder.pop(), e;
1010
1010
  }
@@ -1069,7 +1069,7 @@ class A {
1069
1069
  }
1070
1070
  class D {
1071
1071
  constructor(t = {}) {
1072
- this.width = t.width || 800, this.height = t.height || 600, this.backgroundColor = t.backgroundColor || "#000000", this.canvas = document.createElement("canvas"), this.canvas.width = this.width, this.canvas.height = this.height, this.ctx = this.canvas.getContext("2d"), (t.parent ? typeof t.parent == "string" ? document.querySelector(t.parent) : t.parent : document.body).appendChild(this.canvas);
1072
+ this.width = t.width || 800, this.height = t.height || 600, this.backgroundColor = t.backgroundColor || "#000000", t.canvas ? (this.canvas = t.canvas, this.canvas.width = this.width, this.canvas.height = this.height) : (this.canvas = document.createElement("canvas"), this.canvas.width = this.width, this.canvas.height = this.height, (t.parent ? typeof t.parent == "string" ? document.querySelector(t.parent) : t.parent : document.body).appendChild(this.canvas)), this.ctx = this.canvas.getContext("2d");
1073
1073
  }
1074
1074
  /**
1075
1075
  * Clear the canvas.
@@ -1153,7 +1153,7 @@ class y {
1153
1153
  render(t) {
1154
1154
  }
1155
1155
  }
1156
- class B extends y {
1156
+ class G extends y {
1157
1157
  constructor(t = "box", e = 50, s = 50, i = 25) {
1158
1158
  super(), this.type = t, this.width = e, this.height = s, this.radius = i, this.tag = null;
1159
1159
  }
@@ -1264,7 +1264,7 @@ class _ {
1264
1264
  setGravity(t, e) {
1265
1265
  }
1266
1266
  }
1267
- const G = new _();
1267
+ const $ = new _();
1268
1268
  console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");
1269
1269
  class k {
1270
1270
  constructor() {
@@ -1348,7 +1348,15 @@ class U {
1348
1348
  _registerCoreSystems(t) {
1349
1349
  this.systems.register("ticker", new L(), {
1350
1350
  priority: 100
1351
- }), this.systems.register("renderer", new D(t.renderer || {}), {
1351
+ });
1352
+ const e = {
1353
+ width: t.width,
1354
+ height: t.height,
1355
+ backgroundColor: t.backgroundColor,
1356
+ canvas: t.canvas,
1357
+ ...t.renderer
1358
+ };
1359
+ this.systems.register("renderer", new D(e), {
1352
1360
  priority: 90
1353
1361
  }), this.systems.register("input", new k(), {
1354
1362
  priority: 80
@@ -1587,36 +1595,26 @@ const X = {
1587
1595
  starBurst(a, t, e) {
1588
1596
  }
1589
1597
  };
1590
- class J {
1598
+ class W {
1591
1599
  constructor() {
1592
- this.children = [], this.game = null;
1600
+ this.gameObjects = [], this.kernel = null;
1593
1601
  }
1594
1602
  /**
1595
1603
  * Called when the scene is added to the Game.
1596
1604
  */
1597
1605
  onEnter() {
1598
1606
  }
1599
- onExit() {
1600
- }
1601
1607
  /**
1602
- * Update loop for the scene.
1603
- * @param {number} dt
1608
+ * Called when the scene is removed from the Game.
1604
1609
  */
1605
- update(t) {
1606
- for (const e of this.children)
1607
- e.update && e.update(t);
1610
+ onExit() {
1608
1611
  }
1609
1612
  /**
1610
- this.gameObjects = [];
1611
- this.kernel = null; // Injected by Game
1612
- }
1613
-
1614
- /**
1615
- * Add a GameObject to the scene.
1616
- * @param {GameObject} gameObject
1617
- */
1613
+ * Add a GameObject to the scene.
1614
+ * @param {GameObject} gameObject
1615
+ */
1618
1616
  add(t) {
1619
- return t.kernel = this.kernel, this.gameObjects.push(t), t;
1617
+ return this.kernel && (t.kernel = this.kernel), this.gameObjects.push(t), t;
1620
1618
  }
1621
1619
  /**
1622
1620
  * Remove a GameObject from the scene.
@@ -1626,10 +1624,18 @@ class J {
1626
1624
  const e = this.gameObjects.indexOf(t);
1627
1625
  e > -1 && this.gameObjects.splice(e, 1);
1628
1626
  }
1627
+ /**
1628
+ * Update loop for the scene.
1629
+ * @param {number} dt
1630
+ */
1629
1631
  update(t) {
1630
1632
  for (const e of this.gameObjects)
1631
1633
  e.update(t);
1632
1634
  }
1635
+ /**
1636
+ * Render loop for the scene.
1637
+ * @param {CanvasRenderingContext2D} ctx
1638
+ */
1633
1639
  render(t) {
1634
1640
  for (const e of this.gameObjects)
1635
1641
  e.render(t);
@@ -1647,9 +1653,9 @@ class R {
1647
1653
  this.currentScene && this.currentScene.onExit(), this.currentScene = t, this.currentScene.game = this.game, this.game.scene = t, t.onEnter();
1648
1654
  }
1649
1655
  }
1650
- class W {
1656
+ class J {
1651
1657
  constructor(t = {}) {
1652
- this.config = t, this.kernel = new U(t), this.director = new R(this), this.kernel.events.on(p.Events.TICK, this._update.bind(this), 10), this.kernel.events.on(p.Events.RENDER, this._render.bind(this), 10);
1658
+ this.config = t, this.kernel = new U(t), this.director = new R(this), this.kernel.systems.register("director", this.director), this.kernel.events.on(p.Events.TICK, this._update.bind(this), 10), this.kernel.events.on(p.Events.RENDER, this._render.bind(this), 10);
1653
1659
  }
1654
1660
  /**
1655
1661
  * Backward compatibility accessors
@@ -1700,7 +1706,17 @@ class W {
1700
1706
  }
1701
1707
  class Y {
1702
1708
  constructor(t = 0, e = 0) {
1703
- this.x = t, this.y = e, this.rotation = 0, this.scale = { x: 1, y: 1 }, this.components = [], this.children = [], this.parent = null, this.kernel = null;
1709
+ this.x = t, this.y = e, this.rotation = 0, this.scale = { x: 1, y: 1 }, this.components = [], this.children = [], this.parent = null, this._kernel = null;
1710
+ }
1711
+ get kernel() {
1712
+ return this._kernel;
1713
+ }
1714
+ set kernel(t) {
1715
+ this._kernel = t;
1716
+ for (const e of this.components)
1717
+ e.kernel = t;
1718
+ for (const e of this.children)
1719
+ e.kernel = t;
1704
1720
  }
1705
1721
  /**
1706
1722
  * Add a child object.
@@ -1766,7 +1782,7 @@ class b {
1766
1782
  return Math.sqrt(Math.pow(e.x - t.x, 2) + Math.pow(e.y - t.y, 2));
1767
1783
  }
1768
1784
  }
1769
- class z extends y {
1785
+ class j extends y {
1770
1786
  constructor(t) {
1771
1787
  super(), this.image = t, this.anchor = { x: 0.5, y: 0.5 }, this.width = t ? t.width : 0, this.height = t ? t.height : 0, this.frame = { x: 0, y: 0, w: this.width, h: this.height };
1772
1788
  }
@@ -1799,7 +1815,7 @@ class V extends y {
1799
1815
  super(), this.animations = {}, this.currentAnim = null, this.timer = 0, this.currentFrameIndex = 0, this.sprite = null;
1800
1816
  }
1801
1817
  onAttach() {
1802
- this.sprite = this.gameObject.getComponent(z), this.sprite || console.warn("Animator attached to GameObject without a Sprite component.");
1818
+ this.sprite = this.gameObject.getComponent(j), this.sprite || console.warn("Animator attached to GameObject without a Sprite component.");
1803
1819
  }
1804
1820
  addAnimation(t, e, s = 10, i = !0) {
1805
1821
  this.animations[t] = { frames: e, fps: s, loop: i };
@@ -1842,12 +1858,12 @@ class Q {
1842
1858
  const n = r.getContext("2d");
1843
1859
  for (let o = 0; o < 4; o++) {
1844
1860
  const h = o * 64, c = 0, d = h + 64 / 2, u = c + 64 / 2, m = o % 2 === 0 ? 0 : -2, f = o === 1 ? 5 : o === 3 ? -5 : 0;
1845
- n.fillStyle = t, n.beginPath(), n.arc(d, u + m, 20, 0, Math.PI * 2), n.fill(), n.fillStyle = e, n.beginPath(), n.arc(d - 15, u + m + f, 8, 0, Math.PI * 2), n.arc(d + 15, u + m - f, 8, 0, Math.PI * 2), n.fill(), n.fillStyle = j(t), n.beginPath(), n.arc(d, u + m, 15, 0, Math.PI * 2), n.fill(), e === "#333" && (n.fillStyle = "#000", n.fillRect(d + 10, u + m - 5, 25, 6));
1861
+ n.fillStyle = t, n.beginPath(), n.arc(d, u + m, 20, 0, Math.PI * 2), n.fill(), n.fillStyle = e, n.beginPath(), n.arc(d - 15, u + m + f, 8, 0, Math.PI * 2), n.arc(d + 15, u + m - f, 8, 0, Math.PI * 2), n.fill(), n.fillStyle = z(t), n.beginPath(), n.arc(d, u + m, 15, 0, Math.PI * 2), n.fill(), e === "#333" && (n.fillStyle = "#000", n.fillRect(d + 10, u + m - 5, 25, 6));
1846
1862
  }
1847
1863
  return r;
1848
1864
  }
1849
1865
  }
1850
- function j(a, t) {
1866
+ function z(a, t) {
1851
1867
  return a;
1852
1868
  }
1853
1869
  class Z extends y {
@@ -1910,18 +1926,18 @@ class tt extends y {
1910
1926
  }
1911
1927
  export {
1912
1928
  V as Animator,
1913
- B as Collider,
1929
+ G as Collider,
1914
1930
  y as Component,
1915
1931
  P as DataService,
1916
1932
  R as Director,
1917
1933
  U as DopamineKernel,
1918
1934
  p as EventBus,
1919
- W as Game,
1935
+ J as Game,
1920
1936
  Y as GameObject,
1921
- T as GameUI,
1937
+ C as GameUI,
1922
1938
  F as GlobalInput,
1923
1939
  N as GlobalLoader,
1924
- G as GlobalPhysics,
1940
+ $ as GlobalPhysics,
1925
1941
  H as IAudioSystem,
1926
1942
  q as IParticleSystem,
1927
1943
  X as IPhysicsSystem,
@@ -1929,19 +1945,19 @@ export {
1929
1945
  k as Input,
1930
1946
  S as Loader,
1931
1947
  Z as ParticleEmitter,
1932
- C as ParticleSystem,
1948
+ T as ParticleSystem,
1933
1949
  _ as Physics,
1934
1950
  A as PluginRegistry,
1935
1951
  D as Renderer,
1936
1952
  E as RewardSystem,
1937
- J as Scene,
1953
+ W as Scene,
1938
1954
  tt as ScreenShake,
1939
1955
  I as SoundManager,
1940
- z as Sprite,
1956
+ j as Sprite,
1941
1957
  K as System,
1942
1958
  O as SystemRegistry,
1943
1959
  Q as TextureGenerator,
1944
1960
  L as Ticker,
1945
1961
  b as Vector2,
1946
- $ as default
1962
+ B as default
1947
1963
  };
@@ -42,4 +42,4 @@
42
42
  </div>
43
43
  <button class="btn" onclick="location.reload()">Play Again</button>
44
44
  <button class="btn" onclick="window.location.href='index.html'" style="margin-top: 10px; background: #543847;">Exit</button>
45
- `,document.body.appendChild(t)}}class E{constructor(e={}){this.container=e.container?typeof e.container=="string"?document.querySelector(e.container):e.container:document.body,this.canvasId=e.canvasId||"dopamine-particle-canvas",this.canvas=document.getElementById(this.canvasId),this.canvas||(this.canvas=document.createElement("canvas"),this.canvas.id=this.canvasId,this.canvas.style.pointerEvents="none",this.canvas.style.zIndex=e.zIndex||"9999",this.container===document.body?(this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0"):(this.canvas.style.position="absolute",this.canvas.style.top="0",this.canvas.style.left="0",window.getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative")),this.container.appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.particles=[],this.pool=[],this.sprites=new Map,this.customEffects=new Map,this.isAnimating=!1,this._resize(),window.ResizeObserver&&this.container!==document.body?new ResizeObserver(()=>this._resize()).observe(this.container):window.addEventListener("resize",()=>this._resize())}_resize(){this.container===document.body?(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight):(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}registerSprite(e,t){const s=new Image;s.src=t,this.sprites.set(e,s)}registerEffect(e,t){this.customEffects.set(e,t)}play(e,t,s,...i){const n=this.customEffects.get(e);n?n(t,s,...i):console.warn(`[DopamineJS] Effect '${e}' not found.`)}emit(e){const{x:t,y:s,count:i=10,speed:n=5,gravity:r=.1,decay:h=.02,life:c=1,color:l="#ffd700",sprite:u=null,spread:y=Math.PI*2,angle:p=0,size:w=5}=e;for(let R=0;R<i;R++){const d=this._getParticle(),j=p+(Math.random()-.5)*y,z=Math.random()*n;d.x=t,d.y=s,d.vx=Math.cos(j)*z,d.vy=Math.sin(j)*z,d.life=c,d.decay=h*(.8+Math.random()*.4),d.gravity=r,d.color=Array.isArray(l)?l[Math.floor(Math.random()*l.length)]:l,d.size=w*(.8+Math.random()*.4),d.sprite=u,d.rotation=Math.random()*Math.PI*2,d.rotationSpeed=(Math.random()-.5)*.2,this.particles.push(d)}this._startAnimation()}_getParticle(){return this.pool.length>0?this.pool.pop():{}}_recycleParticle(e){this.pool.push(e)}confetti(e,t,s=50){const i=["#ff6b6b","#4ecdc4","#45b7d1","#f7dc6f","#c06c84","#6c5ce7"];this.emit({x:e,y:t,count:s,color:i,speed:10,gravity:.3,decay:.015,size:8,spread:Math.PI*2})}coinShower(e,t,s=10){this.emit({x:e,y:t,count:s,color:"#ffd700",speed:4,gravity:.4,decay:.012,size:12,angle:-Math.PI/2,spread:Math.PI/2})}sparkle(e,t,s=20,i="#ffd700"){this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.05,decay:.03,size:3})}fire(e,t,s=15){const i=["#ff6b00","#ff8800","#ffaa00","#ff4400"];this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.2,decay:.04,size:5,angle:-Math.PI/2,spread:Math.PI/4})}starBurst(e,t,s=8){for(let i=0;i<s;i++){const n=this._getParticle(),r=Math.PI*2/s*i,h=4;n.x=e,n.y=t,n.vx=Math.cos(r)*h,n.vy=Math.sin(r)*h,n.life=1,n.decay=.03,n.gravity=0,n.color="#ffffff",n.size=15,n.sprite=null,n.type="star",n.rotation=r,n.rotationSpeed=0,this.particles.push(n)}this._startAnimation()}_startAnimation(){this.isAnimating||(this.isAnimating=!0,this._animate())}_animate(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);for(let e=this.particles.length-1;e>=0;e--){const t=this.particles[e];if(t.vy+=t.gravity,t.x+=t.vx,t.y+=t.vy,t.life-=t.decay,t.rotationSpeed&&(t.rotation+=t.rotationSpeed),t.life<=0){this._recycleParticle(t),this.particles.splice(e,1);continue}if(this.ctx.save(),this.ctx.globalAlpha=t.life,this.ctx.translate(t.x,t.y),this.ctx.rotate(t.rotation),t.sprite&&this.sprites.has(t.sprite)){const s=this.sprites.get(t.sprite);s.complete&&this.ctx.drawImage(s,-t.size/2,-t.size/2,t.size,t.size)}else t.type==="star"?(this.ctx.fillStyle=t.color,this._drawStarPath(0,0,5,t.size,t.size/2),this.ctx.fill()):(this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(0,0,t.size,0,Math.PI*2),this.ctx.fill());this.ctx.restore()}this.particles.length>0?requestAnimationFrame(()=>this._animate()):this.isAnimating=!1}_drawStarPath(e,t,s,i,n){let r=Math.PI/2*3,h=e,c=t;const l=Math.PI/s;this.ctx.beginPath(),this.ctx.moveTo(e,t-i);for(let u=0;u<s;u++)h=e+Math.cos(r)*i,c=t+Math.sin(r)*i,this.ctx.lineTo(h,c),r+=l,h=e+Math.cos(r)*n,c=t+Math.sin(r)*n,this.ctx.lineTo(h,c),r+=l;this.ctx.lineTo(e,t-i),this.ctx.closePath()}clear(){this.particles.forEach(e=>this._recycleParticle(e)),this.particles=[],this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}}class T{constructor(e={}){this.audioContext=null,this.storageKey=e.storageKey||"dopamineSoundsMuted",this.muted=localStorage.getItem(this.storageKey)==="true",this.assets=new Map,this.customSounds=e.customSounds||{},Object.keys(this.customSounds).length>0&&this.preloadSounds(this.customSounds)}initAudio(){if(!this.audioContext){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}this.audioContext.state==="suspended"&&this.audioContext.resume()}toggleMute(){return this.muted=!this.muted,localStorage.setItem(this.storageKey,this.muted),this.muted}registerSound(e,t){this.customSounds[e]=t,this.audioContext&&this.loadSound(e,t)}async preloadSounds(e){const t=Object.entries(e).map(([s,i])=>this.loadSound(s,i));await Promise.allSettled(t)}async loadSound(e,t){try{if(!this.audioContext)return;const i=await(await fetch(t)).arrayBuffer(),n=await this.audioContext.decodeAudioData(i);this.assets.set(e,n)}catch(s){console.warn(`[DopamineJS] Failed to load sound '${e}':`,s)}}async play(e){if(this.muted)return;if(this.initAudio(),this.assets.has(e)){this._playBuffer(this.assets.get(e));return}if(this.customSounds[e]&&!this.assets.has(e)&&(await this.loadSound(e,this.customSounds[e]),this.assets.has(e))){this._playBuffer(this.assets.get(e));return}const t={jump:()=>this.playJump(!0),score:()=>this.playScore(!0),success:()=>this.playSuccess(!0),click:()=>this.playClick(!0),error:()=>this.playError(!0),gameover:()=>this.playGameOver(!0)};t[e]&&t[e]()}_playBuffer(e){const t=this.audioContext.createBufferSource();t.buffer=e,t.connect(this.audioContext.destination),t.start(0)}playTone(e,t,s="sine",i=.3){if(this.muted)return;this.initAudio();const n=this.audioContext.createOscillator(),r=this.audioContext.createGain();n.connect(r),r.connect(this.audioContext.destination),n.frequency.value=e,n.type=s,r.gain.setValueAtTime(i,this.audioContext.currentTime),r.gain.exponentialRampToValueAtTime(.01,this.audioContext.currentTime+t),n.start(this.audioContext.currentTime),n.stop(this.audioContext.currentTime+t)}playJump(e=!1){if(!e&&this.assets.has("jump"))return this.play("jump");this.playTone(400,.1,"square",.2)}playScore(e=!1){if(!e&&this.assets.has("score"))return this.play("score");this.playTone(800,.15,"sine",.25),setTimeout(()=>this.playTone(1e3,.15,"sine",.25),50)}playGameOver(e=!1){if(!e&&this.assets.has("gameover"))return this.play("gameover");this.playTone(300,.2,"sawtooth",.3),setTimeout(()=>this.playTone(200,.2,"sawtooth",.3),100),setTimeout(()=>this.playTone(150,.3,"sawtooth",.3),200)}playClick(e=!1){if(!e&&this.assets.has("click"))return this.play("click");this.playTone(600,.05,"sine",.1)}playSuccess(e=!1){if(!e&&this.assets.has("success"))return this.play("success");this.playTone(600,.1,"sine",.2),setTimeout(()=>this.playTone(800,.2,"sine",.2),100)}playError(e=!1){if(!e&&this.assets.has("error"))return this.play("error");this.playTone(200,.2,"sawtooth",.3)}}class G{constructor(e={}){this.config=e,this.dataService=new M(e.data||{}),this.rewardSystem=new b(this.dataService,e.rewards||{}),this.soundManager=new T(e.sound||{}),this.particleSystem=new E(e.particles||{}),this.gameUI=new P(this.particleSystem),this._bindEvents()}async init(){return await this.rewardSystem.init(),console.log("DopamineJS Initialized 🚀"),{rewardSystem:this.rewardSystem,gameUI:this.gameUI,particleSystem:this.particleSystem,soundManager:this.soundManager}}_bindEvents(){this.rewardSystem.on("xp_gained",e=>{const{total:t,needed:s}=this.rewardSystem.getXPForNextLevel();this.gameUI.updateXP(this.rewardSystem.player.xp,s,t),e.xpGained>0}),this.rewardSystem.on("level_up",e=>{this.gameUI.updateLevel(e.newLevel),this.gameUI.showLevelUp(e.oldLevel,e.newLevel)}),this.rewardSystem.on("achievement_unlocked",e=>{this.gameUI.showAchievement(e)}),this.rewardSystem.on("new_high_score",e=>{this.gameUI.showNotification(`New High Score: ${e.score}!`,"legendary"),this.soundManager.playSuccess()})}}class m{constructor(){this._listeners=new Map,this._onceListeners=new Map,this._sortedCache=new Map}on(e,t,s=0){return this._listeners.has(e)||this._listeners.set(e,new Set),this._listeners.get(e).add({callback:t,priority:s}),this._sortedCache.delete(e),this}once(e,t){return this._onceListeners.has(e)||this._onceListeners.set(e,new Set),this._onceListeners.get(e).add(t),this}off(e,t){const s=this._listeners.get(e);if(s){for(const n of s)if(n.callback===t){s.delete(n),this._sortedCache.delete(e);break}}const i=this._onceListeners.get(e);return i&&i.delete(t),this}emit(e,t){const s=this._getSortedListeners(e);for(let n=0;n<s.length;n++)s[n].callback(t);const i=this._onceListeners.get(e);if(i&&i.size>0){for(const n of i)n(t);i.clear()}}_getSortedListeners(e){if(this._sortedCache.has(e))return this._sortedCache.get(e);const t=this._listeners.get(e);if(!t||t.size===0)return[];const s=Array.from(t).sort((i,n)=>n.priority-i.priority);return this._sortedCache.set(e,s),s}clear(e){e?(this._listeners.delete(e),this._onceListeners.delete(e),this._sortedCache.delete(e)):(this._listeners.clear(),this._onceListeners.clear(),this._sortedCache.clear())}hasListeners(e){const t=this._listeners.get(e),s=this._onceListeners.get(e);return t&&t.size>0||s&&s.size>0}}m.Events={TICK:"tick",FIXED_UPDATE:"fixed_update",RENDER:"render",COLLISION_ENTER:"collision_enter",COLLISION_EXIT:"collision_exit",XP_GAINED:"xp_gained",LEVEL_UP:"level_up",ACHIEVEMENT_UNLOCKED:"achievement_unlocked",NEW_HIGH_SCORE:"new_high_score",STREAK_UPDATED:"streak_updated",SYSTEM_REGISTERED:"system_registered",SYSTEM_UNREGISTERED:"system_unregistered",PLUGIN_LOADED:"plugin_loaded",PLUGIN_UNLOADED:"plugin_unloaded"};class I{constructor(e){this.kernel=e,this._systems=new Map,this._updateOrder=[],this._fixedUpdateOrder=[],this._needsRecompute=!1}register(e,t,{priority:s=0,dependencies:i=[]}={}){this._systems.has(e)&&(console.warn(`[SystemRegistry] System "${e}" already registered. Replacing.`),this.unregister(e));for(const n of i)this._systems.has(n)||console.warn(`[SystemRegistry] Dependency "${n}" not found for system "${e}"`);return this._systems.set(e,{system:t,priority:s,dependencies:i}),t.init&&t.init(this.kernel),this._needsRecompute=!0,this.kernel.events.emit("system_registered",{name:e,system:t}),this}get(e){const t=this._systems.get(e);return t?t.system:void 0}has(e){return this._systems.has(e)}unregister(e){const t=this._systems.get(e);return t?(t.system.destroy&&t.system.destroy(),this._systems.delete(e),this._needsRecompute=!0,this.kernel.events.emit("system_unregistered",{name:e}),!0):!1}update(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._updateOrder.length;t++){const s=this._updateOrder[t];s.update&&s.update(e)}}fixedUpdate(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._fixedUpdateOrder.length;t++){const s=this._fixedUpdateOrder[t];s.fixedUpdate&&s.fixedUpdate(e)}}_recomputeUpdateOrder(){const e=Array.from(this._systems.entries()),t=new Map,s=new Map;for(const[r,h]of e)t.set(r,h.dependencies),s.set(r,0);for(const[r,h]of t)for(const c of h)s.has(c)&&s.set(r,s.get(r)+1);const i=[],n=[];for(const[r,h]of s)h===0&&i.push(r);for(;i.length>0;){i.sort((h,c)=>{const l=this._systems.get(h).priority;return this._systems.get(c).priority-l});const r=i.shift();n.push(r);for(const[h,c]of t)if(c.includes(r)){const l=s.get(h)-1;s.set(h,l),l===0&&i.push(h)}}n.length!==e.length&&(console.error("[SystemRegistry] Circular dependency detected in systems!"),n.length=0,n.push(...e.map(([r])=>r).sort((r,h)=>this._systems.get(h).priority-this._systems.get(r).priority))),this._updateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.update),this._fixedUpdateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.fixedUpdate),this._needsRecompute=!1}getSystemNames(){return Array.from(this._systems.keys())}clear(){for(const e of this._systems.keys())this.unregister(e)}}class C{constructor(e){this.kernel=e,this._plugins=new Map,this._loadOrder=[]}use(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version}),console.log(`[PluginRegistry] Loaded plugin: ${e.name}${e.version?` v${e.version}`:""}`)}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}async useAsync(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{await e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version}),console.log(`[PluginRegistry] Loaded plugin: ${e.name}${e.version?` v${e.version}`:""}`)}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}remove(e){const t=this._plugins.get(e);if(!t)return!1;if(t.destroy)try{t.destroy()}catch(i){console.error(`[PluginRegistry] Error destroying plugin "${e}":`,i)}this._plugins.delete(e);const s=this._loadOrder.indexOf(e);return s>-1&&this._loadOrder.splice(s,1),this.kernel.events.emit("plugin_unloaded",{name:e}),!0}get(e){return this._plugins.get(e)}has(e){return this._plugins.has(e)}getPluginNames(){return Array.from(this._plugins.keys())}getLoadOrder(){return[...this._loadOrder]}clear(){for(let e=this._loadOrder.length-1;e>=0;e--)this.remove(this._loadOrder[e])}}class O{constructor(e={}){this.width=e.width||800,this.height=e.height||600,this.backgroundColor=e.backgroundColor||"#000000",this.canvas=document.createElement("canvas"),this.canvas.width=this.width,this.canvas.height=this.height,this.ctx=this.canvas.getContext("2d"),(e.parent?typeof e.parent=="string"?document.querySelector(e.parent):e.parent:document.body).appendChild(this.canvas)}clear(){this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}resize(e,t){this.width=e,this.height=t,this.canvas.width=e,this.canvas.height=t}}class A{constructor(){this.running=!1,this.lastTime=0,this.callbacks=new Set,this._tick=this._tick.bind(this)}add(e){this.callbacks.add(e)}remove(e){this.callbacks.delete(e)}start(){this.running||(this.running=!0,this.lastTime=performance.now(),requestAnimationFrame(this._tick))}stop(){this.running=!1}_tick(e){if(!this.running)return;const t=(e-this.lastTime)/1e3;this.lastTime=e;const s=Math.min(t,.1);for(const i of this.callbacks)i(s);requestAnimationFrame(this._tick)}}class f{constructor(){this.gameObject=null,this.kernel=null}get physics(){var e;return(e=this.kernel)==null?void 0:e.systems.get("physics")}get input(){var e;return(e=this.kernel)==null?void 0:e.systems.get("input")}get loader(){var e;return(e=this.kernel)==null?void 0:e.systems.get("loader")}get events(){var e;return(e=this.kernel)==null?void 0:e.events}onAttach(){}onDetach(){}update(e){}render(e){}}class $ extends f{constructor(e="box",t=50,s=50,i=25){super(),this.type=e,this.width=t,this.height=s,this.radius=i,this.tag=null}onAttach(){super.onAttach(),this.physics&&this.physics.add(this)}onDetach(){super.onDetach(),this.physics&&this.physics.remove(this)}getBounds(){const e=this.gameObject;if(this.type==="box")return{left:e.x-this.width/2,right:e.x+this.width/2,top:e.y-this.height/2,bottom:e.y+this.height/2};if(this.type==="circle")return{x:e.x,y:e.y,radius:this.radius}}}class _{constructor(){this.colliders=[],this.kernel=null}init(e){this.kernel=e}fixedUpdate(e){this.step()}destroy(){this.colliders=[]}add(e){this.colliders.push(e)}remove(e){const t=this.colliders.indexOf(e);t>-1&&this.colliders.splice(t,1)}step(){for(let e=0;e<this.colliders.length;e++)for(let t=e+1;t<this.colliders.length;t++){const s=this.colliders[e],i=this.colliders[t];this._intersects(s,s.getBounds(),i,i.getBounds())&&(this._notifyCollision(s.gameObject,i.gameObject),this._notifyCollision(i.gameObject,s.gameObject))}}_notifyCollision(e,t){!e||!e.components||e.components.forEach(s=>{s.onCollisionEnter&&s.onCollisionEnter(t)})}checkOverlap(e,t){const s=[],i=e.getBounds();for(const n of this.colliders){if(n===e||t&&n.tag!==t)continue;const r=n.getBounds();this._intersects(e,i,n,r)&&s.push(n)}return s}_intersects(e,t,s,i){if(e.type==="box"&&s.type==="box")return t.left<i.right&&t.right>i.left&&t.top<i.bottom&&t.bottom>i.top;if(e.type==="circle"&&s.type==="circle"){const n=t.x-i.x,r=t.y-i.y;return Math.sqrt(n*n+r*r)<t.radius+i.radius}return!1}addBody(e){this.add(e)}removeBody(e){this.remove(e)}checkCollision(e,t){return this._intersects(e,e.getBounds(),t,t.getBounds())}raycast(e,t,s){return null}setGravity(e,t){}}const B=new _;console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");class x{constructor(){this.keys=new Map,this.mouse={x:0,y:0,buttons:new Map},this.kernel=null,this._onKeyDown=this._onKeyDown.bind(this),this._onKeyUp=this._onKeyUp.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseDown=this._onMouseDown.bind(this),this._onMouseUp=this._onMouseUp.bind(this)}init(e){this.kernel=e,window.addEventListener("keydown",this._onKeyDown),window.addEventListener("keyup",this._onKeyUp),window.addEventListener("mousemove",this._onMouseMove),window.addEventListener("mousedown",this._onMouseDown),window.addEventListener("mouseup",this._onMouseUp)}destroy(){window.removeEventListener("keydown",this._onKeyDown),window.removeEventListener("keyup",this._onKeyUp),window.removeEventListener("mousemove",this._onMouseMove),window.removeEventListener("mousedown",this._onMouseDown),window.removeEventListener("mouseup",this._onMouseUp)}_onKeyDown(e){this.keys.set(e.key,!0)}_onKeyUp(e){this.keys.set(e.key,!1)}_onMouseMove(e){this.mouse.x=e.clientX,this.mouse.y=e.clientY}_onMouseDown(e){this.mouse.buttons.set(e.button,!0)}_onMouseUp(e){this.mouse.buttons.set(e.button,!1)}isKeyDown(e){return this.keys.get(e)||!1}isMouseButtonDown(e=0){return this.mouse.buttons.get(e)||!1}}const F=new x;console.warn("[DopamineJS] GlobalInput is deprecated. Use kernel.input instead.");class S{constructor(){this.assets=new Map,this.kernel=null}init(e){this.kernel=e}destroy(){this.assets.clear()}async loadImage(e,t){return new Promise((s,i)=>{const n=new Image;n.onload=()=>{this.assets.set(e,n),s(n)},n.onerror=i,n.src=t})}get(e){return this.assets.get(e)}}const N=new S;console.warn("[DopamineJS] GlobalLoader is deprecated. Use kernel.loader instead.");class D{constructor(e={}){this.config=e,this.events=new m,this.systems=new I(this),this.plugins=new C(this),this._registerCoreSystems(e),this.fixedTimestep=e.fixedTimestep||1/60,this._accumulator=0,this._maxAccumulator=this.fixedTimestep*5}_registerCoreSystems(e){this.systems.register("ticker",new A,{priority:100}),this.systems.register("renderer",new O(e.renderer||{}),{priority:90}),this.systems.register("input",new x,{priority:80}),this.systems.register("loader",new S,{priority:70}),this.systems.register("physics",new _,{priority:60})}start(){const e=this.systems.get("ticker");e&&(e.add(this._update.bind(this)),e.start()),this.events.emit("kernel_started")}stop(){const e=this.systems.get("ticker");e&&e.stop(),this.events.emit("kernel_stopped")}_update(e){for(this.events.emit(m.Events.TICK,{dt:e}),this._accumulator+=e,this._accumulator>this._maxAccumulator&&(this._accumulator=this._maxAccumulator);this._accumulator>=this.fixedTimestep;)this.events.emit(m.Events.FIXED_UPDATE,{dt:this.fixedTimestep}),this.systems.fixedUpdate(this.fixedTimestep),this._accumulator-=this.fixedTimestep;this.systems.update(e),this.events.emit(m.Events.RENDER,{dt:e})}get physics(){return this.systems.get("physics")}get input(){return this.systems.get("input")}get loader(){return this.systems.get("loader")}get renderer(){return this.systems.get("renderer")}get ticker(){return this.systems.get("ticker")}destroy(){this.stop(),this.plugins.clear(),this.systems.clear(),this.events.clear()}}const v={init(a){},update(a){},fixedUpdate(a){},destroy(){}};class K{constructor(){this.kernel=null}init(e){this.kernel=e}update(e){}fixedUpdate(e){}destroy(){}}const X={...v,addBody(a){},removeBody(a){},checkCollision(a,e){},raycast(a,e,t){},setGravity(a,e){},step(a){}},H={...v,registerSound(a,e){},preloadSounds(a){},play(a,e){},playTone(a,e,t,s){},stop(a){},toggleMute(){},setVolume(a){}},q={...v,registerSprite(a,e){},registerEffect(a,e){},play(a,e,t,...s){},emit(a){},clear(){},confetti(a,e,t){},coinShower(a,e,t){},sparkle(a,e,t,s){},fire(a,e,t){},starBurst(a,e,t){}};class J{constructor(){this.children=[],this.game=null}onEnter(){}onExit(){}update(e){for(const t of this.children)t.update&&t.update(e)}add(e){return e.kernel=this.kernel,this.gameObjects.push(e),e}remove(e){const t=this.gameObjects.indexOf(e);t>-1&&this.gameObjects.splice(t,1)}update(e){for(const t of this.gameObjects)t.update(e)}render(e){for(const t of this.gameObjects)t.render(e)}}class L{constructor(e){this.game=e,this.currentScene=null}run(e){this.currentScene&&this.currentScene.onExit(),this.currentScene=e,this.currentScene.game=this.game,this.game.scene=e,e.onEnter()}}class W{constructor(e={}){this.config=e,this.kernel=new D(e),this.director=new L(this),this.kernel.events.on(m.Events.TICK,this._update.bind(this),10),this.kernel.events.on(m.Events.RENDER,this._render.bind(this),10)}get renderer(){return this.kernel.renderer}get ticker(){return this.kernel.ticker}get physics(){return this.kernel.physics}get input(){return this.kernel.input}start(){this.kernel.start()}stop(){this.kernel.stop()}setScene(e){e.kernel=this.kernel,this.director.run(e)}_update({dt:e}){this.director.currentScene&&this.director.currentScene.update(e)}_render({dt:e}){this.renderer.clear(),this.director.currentScene&&this.director.currentScene.render(this.renderer.ctx)}destroy(){this.kernel.destroy()}}class Y{constructor(e=0,t=0){this.x=e,this.y=t,this.rotation=0,this.scale={x:1,y:1},this.components=[],this.children=[],this.parent=null,this.kernel=null}addChild(e){return e.parent=this,e.kernel=this.kernel,this.children.push(e),e}addComponent(e){return e.gameObject=this,e.kernel=this.kernel,this.components.push(e),e.onAttach(),e}getComponent(e){return this.components.find(t=>t instanceof e)}update(e){for(const t of this.components)t.update&&t.update(e);for(const t of this.children)t.update(e)}render(e){e.save(),e.translate(this.x,this.y),e.rotate(this.rotation),e.scale(this.scale.x,this.scale.y);for(const t of this.components)t.render&&t.render(e);for(const t of this.children)t.render(e);e.restore()}}class k{constructor(e=0,t=0){this.x=e,this.y=t}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}scale(e){return this.x*=e,this.y*=e,this}distance(e){const t=this.x-e.x,s=this.y-e.y;return Math.sqrt(t*t+s*s)}normalize(){const e=Math.sqrt(this.x*this.x+this.y*this.y);return e>0&&(this.x/=e,this.y/=e),this}clone(){return new k(this.x,this.y)}static distance(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}}class U extends f{constructor(e){super(),this.image=e,this.anchor={x:.5,y:.5},this.width=e?e.width:0,this.height=e?e.height:0,this.frame={x:0,y:0,w:this.width,h:this.height}}setFrame(e,t,s,i){this.frame={x:e,y:t,w:s,h:i},this.width=s,this.height=i}setTexture(e){this.image=e,e&&this.setFrame(0,0,e.width,e.height)}render(e){if(!this.image)return;const t=this.frame.w,s=this.frame.h,i=-t*this.anchor.x,n=-s*this.anchor.y;e.drawImage(this.image,this.frame.x,this.frame.y,t,s,i,n,t,s)}}class V extends f{constructor(){super(),this.animations={},this.currentAnim=null,this.timer=0,this.currentFrameIndex=0,this.sprite=null}onAttach(){this.sprite=this.gameObject.getComponent(U),this.sprite||console.warn("Animator attached to GameObject without a Sprite component.")}addAnimation(e,t,s=10,i=!0){this.animations[e]={frames:t,fps:s,loop:i}}play(e){this.currentAnim&&this.currentAnim.name===e||this.animations[e]&&(this.currentAnim={name:e,...this.animations[e]},this.currentFrameIndex=0,this.timer=0,this._updateFrame())}update(e){if(!this.currentAnim||!this.sprite)return;this.timer+=e;const t=1/this.currentAnim.fps;this.timer>=t&&(this.timer-=t,this.currentFrameIndex++,this.currentFrameIndex>=this.currentAnim.frames.length&&(this.currentAnim.loop?this.currentFrameIndex=0:this.currentFrameIndex=this.currentAnim.frames.length-1),this._updateFrame())}_updateFrame(){const e=this.currentAnim.frames[this.currentFrameIndex];this.sprite.setFrame(e.x,e.y,e.w,e.h)}}class Q{static createGround(e,t,s="#333"){const i=document.createElement("canvas");i.width=e,i.height=t;const n=i.getContext("2d");n.fillStyle=s,n.fillRect(0,0,e,t);for(let r=0;r<1e3;r++){n.fillStyle=Math.random()>.5?"#444":"#222";const h=Math.random()*4+2;n.fillRect(Math.random()*e,Math.random()*t,h,h)}n.strokeStyle="rgba(255,255,255,0.05)",n.lineWidth=2,n.beginPath();for(let r=0;r<=e;r+=64)n.moveTo(r,0),n.lineTo(r,t);for(let r=0;r<=t;r+=64)n.moveTo(0,r),n.lineTo(e,r);return n.stroke(),i}static createCharacterSheet(e,t){const n=document.createElement("canvas");n.width=64*4,n.height=64;const r=n.getContext("2d");for(let h=0;h<4;h++){const c=h*64,l=0,u=c+64/2,y=l+64/2,p=h%2===0?0:-2,w=h===1?5:h===3?-5:0;r.fillStyle=e,r.beginPath(),r.arc(u,y+p,20,0,Math.PI*2),r.fill(),r.fillStyle=t,r.beginPath(),r.arc(u-15,y+p+w,8,0,Math.PI*2),r.arc(u+15,y+p-w,8,0,Math.PI*2),r.fill(),r.fillStyle=Z(e),r.beginPath(),r.arc(u,y+p,15,0,Math.PI*2),r.fill(),t==="#333"&&(r.fillStyle="#000",r.fillRect(u+10,y+p-5,25,6))}return n}}function Z(a,e){return a}class ee extends f{constructor(e){super(),this.system=e}play(e,t={}){const s=this.gameObject.x,i=this.gameObject.y;switch(e){case"confetti":this.system.confetti(s,i,t.count);break;case"fire":this.system.fire(s,i,t.count);break;case"sparkle":this.system.sparkle(s,i,t.count,t.color);break;case"blood":this.system.emit({x:s,y:i,count:10,color:["#8a0303","#ff0000"],speed:4,gravity:.1,decay:.05});break;default:this.system.emit({x:s,y:i,...t})}}}class te extends f{constructor(){super(),this.intensity=0,this.duration=0,this.timer=0,this.originalPos={x:0,y:0},this.isShaking=!1}shake(e=5,t=.2){this.intensity=e,this.duration=t,this.timer=0,this.isShaking=!0,this.timer===0&&(this.originalPos.x=this.gameObject.x,this.originalPos.y=this.gameObject.y)}update(e){if(!this.isShaking)return;if(this.timer+=e,this.timer>=this.duration){this.isShaking=!1,this.gameObject.x=this.originalPos.x,this.gameObject.y=this.originalPos.y;return}const t=(Math.random()-.5)*2*this.intensity,s=(Math.random()-.5)*2*this.intensity;this.gameObject.x=this.originalPos.x+t,this.gameObject.y=this.originalPos.y+s}}o.Animator=V,o.Collider=$,o.Component=f,o.DataService=M,o.Director=L,o.DopamineKernel=D,o.EventBus=m,o.Game=W,o.GameObject=Y,o.GameUI=P,o.GlobalInput=F,o.GlobalLoader=N,o.GlobalPhysics=B,o.IAudioSystem=H,o.IParticleSystem=q,o.IPhysicsSystem=X,o.ISystem=v,o.Input=x,o.Loader=S,o.ParticleEmitter=ee,o.ParticleSystem=E,o.Physics=_,o.PluginRegistry=C,o.Renderer=O,o.RewardSystem=b,o.Scene=J,o.ScreenShake=te,o.SoundManager=T,o.Sprite=U,o.System=K,o.SystemRegistry=I,o.TextureGenerator=Q,o.Ticker=A,o.Vector2=k,o.default=G,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
45
+ `,document.body.appendChild(t)}}class E{constructor(e={}){this.container=e.container?typeof e.container=="string"?document.querySelector(e.container):e.container:document.body,this.canvasId=e.canvasId||"dopamine-particle-canvas",this.canvas=document.getElementById(this.canvasId),this.canvas||(this.canvas=document.createElement("canvas"),this.canvas.id=this.canvasId,this.canvas.style.pointerEvents="none",this.canvas.style.zIndex=e.zIndex||"9999",this.container===document.body?(this.canvas.style.position="fixed",this.canvas.style.top="0",this.canvas.style.left="0"):(this.canvas.style.position="absolute",this.canvas.style.top="0",this.canvas.style.left="0",window.getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative")),this.container.appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d"),this.particles=[],this.pool=[],this.sprites=new Map,this.customEffects=new Map,this.isAnimating=!1,this._resize(),window.ResizeObserver&&this.container!==document.body?new ResizeObserver(()=>this._resize()).observe(this.container):window.addEventListener("resize",()=>this._resize())}_resize(){this.container===document.body?(this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight):(this.canvas.width=this.container.clientWidth,this.canvas.height=this.container.clientHeight)}registerSprite(e,t){const s=new Image;s.src=t,this.sprites.set(e,s)}registerEffect(e,t){this.customEffects.set(e,t)}play(e,t,s,...i){const n=this.customEffects.get(e);n?n(t,s,...i):console.warn(`[DopamineJS] Effect '${e}' not found.`)}emit(e){const{x:t,y:s,count:i=10,speed:n=5,gravity:r=.1,decay:h=.02,life:c=1,color:l="#ffd700",sprite:u=null,spread:y=Math.PI*2,angle:p=0,size:w=5}=e;for(let R=0;R<i;R++){const d=this._getParticle(),j=p+(Math.random()-.5)*y,z=Math.random()*n;d.x=t,d.y=s,d.vx=Math.cos(j)*z,d.vy=Math.sin(j)*z,d.life=c,d.decay=h*(.8+Math.random()*.4),d.gravity=r,d.color=Array.isArray(l)?l[Math.floor(Math.random()*l.length)]:l,d.size=w*(.8+Math.random()*.4),d.sprite=u,d.rotation=Math.random()*Math.PI*2,d.rotationSpeed=(Math.random()-.5)*.2,this.particles.push(d)}this._startAnimation()}_getParticle(){return this.pool.length>0?this.pool.pop():{}}_recycleParticle(e){this.pool.push(e)}confetti(e,t,s=50){const i=["#ff6b6b","#4ecdc4","#45b7d1","#f7dc6f","#c06c84","#6c5ce7"];this.emit({x:e,y:t,count:s,color:i,speed:10,gravity:.3,decay:.015,size:8,spread:Math.PI*2})}coinShower(e,t,s=10){this.emit({x:e,y:t,count:s,color:"#ffd700",speed:4,gravity:.4,decay:.012,size:12,angle:-Math.PI/2,spread:Math.PI/2})}sparkle(e,t,s=20,i="#ffd700"){this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.05,decay:.03,size:3})}fire(e,t,s=15){const i=["#ff6b00","#ff8800","#ffaa00","#ff4400"];this.emit({x:e,y:t,count:s,color:i,speed:3,gravity:-.2,decay:.04,size:5,angle:-Math.PI/2,spread:Math.PI/4})}starBurst(e,t,s=8){for(let i=0;i<s;i++){const n=this._getParticle(),r=Math.PI*2/s*i,h=4;n.x=e,n.y=t,n.vx=Math.cos(r)*h,n.vy=Math.sin(r)*h,n.life=1,n.decay=.03,n.gravity=0,n.color="#ffffff",n.size=15,n.sprite=null,n.type="star",n.rotation=r,n.rotationSpeed=0,this.particles.push(n)}this._startAnimation()}_startAnimation(){this.isAnimating||(this.isAnimating=!0,this._animate())}_animate(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);for(let e=this.particles.length-1;e>=0;e--){const t=this.particles[e];if(t.vy+=t.gravity,t.x+=t.vx,t.y+=t.vy,t.life-=t.decay,t.rotationSpeed&&(t.rotation+=t.rotationSpeed),t.life<=0){this._recycleParticle(t),this.particles.splice(e,1);continue}if(this.ctx.save(),this.ctx.globalAlpha=t.life,this.ctx.translate(t.x,t.y),this.ctx.rotate(t.rotation),t.sprite&&this.sprites.has(t.sprite)){const s=this.sprites.get(t.sprite);s.complete&&this.ctx.drawImage(s,-t.size/2,-t.size/2,t.size,t.size)}else t.type==="star"?(this.ctx.fillStyle=t.color,this._drawStarPath(0,0,5,t.size,t.size/2),this.ctx.fill()):(this.ctx.fillStyle=t.color,this.ctx.beginPath(),this.ctx.arc(0,0,t.size,0,Math.PI*2),this.ctx.fill());this.ctx.restore()}this.particles.length>0?requestAnimationFrame(()=>this._animate()):this.isAnimating=!1}_drawStarPath(e,t,s,i,n){let r=Math.PI/2*3,h=e,c=t;const l=Math.PI/s;this.ctx.beginPath(),this.ctx.moveTo(e,t-i);for(let u=0;u<s;u++)h=e+Math.cos(r)*i,c=t+Math.sin(r)*i,this.ctx.lineTo(h,c),r+=l,h=e+Math.cos(r)*n,c=t+Math.sin(r)*n,this.ctx.lineTo(h,c),r+=l;this.ctx.lineTo(e,t-i),this.ctx.closePath()}clear(){this.particles.forEach(e=>this._recycleParticle(e)),this.particles=[],this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}}class T{constructor(e={}){this.audioContext=null,this.storageKey=e.storageKey||"dopamineSoundsMuted",this.muted=localStorage.getItem(this.storageKey)==="true",this.assets=new Map,this.customSounds=e.customSounds||{},Object.keys(this.customSounds).length>0&&this.preloadSounds(this.customSounds)}initAudio(){if(!this.audioContext){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}this.audioContext.state==="suspended"&&this.audioContext.resume()}toggleMute(){return this.muted=!this.muted,localStorage.setItem(this.storageKey,this.muted),this.muted}registerSound(e,t){this.customSounds[e]=t,this.audioContext&&this.loadSound(e,t)}async preloadSounds(e){const t=Object.entries(e).map(([s,i])=>this.loadSound(s,i));await Promise.allSettled(t)}async loadSound(e,t){try{if(!this.audioContext)return;const i=await(await fetch(t)).arrayBuffer(),n=await this.audioContext.decodeAudioData(i);this.assets.set(e,n)}catch(s){console.warn(`[DopamineJS] Failed to load sound '${e}':`,s)}}async play(e){if(this.muted)return;if(this.initAudio(),this.assets.has(e)){this._playBuffer(this.assets.get(e));return}if(this.customSounds[e]&&!this.assets.has(e)&&(await this.loadSound(e,this.customSounds[e]),this.assets.has(e))){this._playBuffer(this.assets.get(e));return}const t={jump:()=>this.playJump(!0),score:()=>this.playScore(!0),success:()=>this.playSuccess(!0),click:()=>this.playClick(!0),error:()=>this.playError(!0),gameover:()=>this.playGameOver(!0)};t[e]&&t[e]()}_playBuffer(e){const t=this.audioContext.createBufferSource();t.buffer=e,t.connect(this.audioContext.destination),t.start(0)}playTone(e,t,s="sine",i=.3){if(this.muted)return;this.initAudio();const n=this.audioContext.createOscillator(),r=this.audioContext.createGain();n.connect(r),r.connect(this.audioContext.destination),n.frequency.value=e,n.type=s,r.gain.setValueAtTime(i,this.audioContext.currentTime),r.gain.exponentialRampToValueAtTime(.01,this.audioContext.currentTime+t),n.start(this.audioContext.currentTime),n.stop(this.audioContext.currentTime+t)}playJump(e=!1){if(!e&&this.assets.has("jump"))return this.play("jump");this.playTone(400,.1,"square",.2)}playScore(e=!1){if(!e&&this.assets.has("score"))return this.play("score");this.playTone(800,.15,"sine",.25),setTimeout(()=>this.playTone(1e3,.15,"sine",.25),50)}playGameOver(e=!1){if(!e&&this.assets.has("gameover"))return this.play("gameover");this.playTone(300,.2,"sawtooth",.3),setTimeout(()=>this.playTone(200,.2,"sawtooth",.3),100),setTimeout(()=>this.playTone(150,.3,"sawtooth",.3),200)}playClick(e=!1){if(!e&&this.assets.has("click"))return this.play("click");this.playTone(600,.05,"sine",.1)}playSuccess(e=!1){if(!e&&this.assets.has("success"))return this.play("success");this.playTone(600,.1,"sine",.2),setTimeout(()=>this.playTone(800,.2,"sine",.2),100)}playError(e=!1){if(!e&&this.assets.has("error"))return this.play("error");this.playTone(200,.2,"sawtooth",.3)}}class G{constructor(e={}){this.config=e,this.dataService=new M(e.data||{}),this.rewardSystem=new b(this.dataService,e.rewards||{}),this.soundManager=new T(e.sound||{}),this.particleSystem=new E(e.particles||{}),this.gameUI=new P(this.particleSystem),this._bindEvents()}async init(){return await this.rewardSystem.init(),{rewardSystem:this.rewardSystem,gameUI:this.gameUI,particleSystem:this.particleSystem,soundManager:this.soundManager}}_bindEvents(){this.rewardSystem.on("xp_gained",e=>{const{total:t,needed:s}=this.rewardSystem.getXPForNextLevel();this.gameUI.updateXP(this.rewardSystem.player.xp,s,t),e.xpGained>0}),this.rewardSystem.on("level_up",e=>{this.gameUI.updateLevel(e.newLevel),this.gameUI.showLevelUp(e.oldLevel,e.newLevel)}),this.rewardSystem.on("achievement_unlocked",e=>{this.gameUI.showAchievement(e)}),this.rewardSystem.on("new_high_score",e=>{this.gameUI.showNotification(`New High Score: ${e.score}!`,"legendary"),this.soundManager.playSuccess()})}}class m{constructor(){this._listeners=new Map,this._onceListeners=new Map,this._sortedCache=new Map}on(e,t,s=0){return this._listeners.has(e)||this._listeners.set(e,new Set),this._listeners.get(e).add({callback:t,priority:s}),this._sortedCache.delete(e),this}once(e,t){return this._onceListeners.has(e)||this._onceListeners.set(e,new Set),this._onceListeners.get(e).add(t),this}off(e,t){const s=this._listeners.get(e);if(s){for(const n of s)if(n.callback===t){s.delete(n),this._sortedCache.delete(e);break}}const i=this._onceListeners.get(e);return i&&i.delete(t),this}emit(e,t){const s=this._getSortedListeners(e);for(let n=0;n<s.length;n++)s[n].callback(t);const i=this._onceListeners.get(e);if(i&&i.size>0){for(const n of i)n(t);i.clear()}}_getSortedListeners(e){if(this._sortedCache.has(e))return this._sortedCache.get(e);const t=this._listeners.get(e);if(!t||t.size===0)return[];const s=Array.from(t).sort((i,n)=>n.priority-i.priority);return this._sortedCache.set(e,s),s}clear(e){e?(this._listeners.delete(e),this._onceListeners.delete(e),this._sortedCache.delete(e)):(this._listeners.clear(),this._onceListeners.clear(),this._sortedCache.clear())}hasListeners(e){const t=this._listeners.get(e),s=this._onceListeners.get(e);return t&&t.size>0||s&&s.size>0}}m.Events={TICK:"tick",FIXED_UPDATE:"fixed_update",RENDER:"render",COLLISION_ENTER:"collision_enter",COLLISION_EXIT:"collision_exit",XP_GAINED:"xp_gained",LEVEL_UP:"level_up",ACHIEVEMENT_UNLOCKED:"achievement_unlocked",NEW_HIGH_SCORE:"new_high_score",STREAK_UPDATED:"streak_updated",SYSTEM_REGISTERED:"system_registered",SYSTEM_UNREGISTERED:"system_unregistered",PLUGIN_LOADED:"plugin_loaded",PLUGIN_UNLOADED:"plugin_unloaded"};class I{constructor(e){this.kernel=e,this._systems=new Map,this._updateOrder=[],this._fixedUpdateOrder=[],this._needsRecompute=!1}register(e,t,{priority:s=0,dependencies:i=[]}={}){this._systems.has(e)&&(console.warn(`[SystemRegistry] System "${e}" already registered. Replacing.`),this.unregister(e));for(const n of i)this._systems.has(n)||console.warn(`[SystemRegistry] Dependency "${n}" not found for system "${e}"`);return this._systems.set(e,{system:t,priority:s,dependencies:i}),t.init&&t.init(this.kernel),this._needsRecompute=!0,this.kernel.events.emit("system_registered",{name:e,system:t}),this}get(e){const t=this._systems.get(e);return t?t.system:void 0}has(e){return this._systems.has(e)}unregister(e){const t=this._systems.get(e);return t?(t.system.destroy&&t.system.destroy(),this._systems.delete(e),this._needsRecompute=!0,this.kernel.events.emit("system_unregistered",{name:e}),!0):!1}update(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._updateOrder.length;t++){const s=this._updateOrder[t];s.update&&s.update(e)}}fixedUpdate(e){this._needsRecompute&&this._recomputeUpdateOrder();for(let t=0;t<this._fixedUpdateOrder.length;t++){const s=this._fixedUpdateOrder[t];s.fixedUpdate&&s.fixedUpdate(e)}}_recomputeUpdateOrder(){const e=Array.from(this._systems.entries()),t=new Map,s=new Map;for(const[r,h]of e)t.set(r,h.dependencies),s.set(r,0);for(const[r,h]of t)for(const c of h)s.has(c)&&s.set(r,s.get(r)+1);const i=[],n=[];for(const[r,h]of s)h===0&&i.push(r);for(;i.length>0;){i.sort((h,c)=>{const l=this._systems.get(h).priority;return this._systems.get(c).priority-l});const r=i.shift();n.push(r);for(const[h,c]of t)if(c.includes(r)){const l=s.get(h)-1;s.set(h,l),l===0&&i.push(h)}}n.length!==e.length&&(console.error("[SystemRegistry] Circular dependency detected in systems!"),n.length=0,n.push(...e.map(([r])=>r).sort((r,h)=>this._systems.get(h).priority-this._systems.get(r).priority))),this._updateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.update),this._fixedUpdateOrder=n.map(r=>this._systems.get(r).system).filter(r=>r.fixedUpdate),this._needsRecompute=!1}getSystemNames(){return Array.from(this._systems.keys())}clear(){for(const e of this._systems.keys())this.unregister(e)}}class C{constructor(e){this.kernel=e,this._plugins=new Map,this._loadOrder=[]}use(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version})}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}async useAsync(e){if(!e.name)throw new Error("[PluginRegistry] Plugin must have a name");if(this._plugins.has(e.name))return console.warn(`[PluginRegistry] Plugin "${e.name}" already registered. Skipping.`),this;if(!e.init||typeof e.init!="function")throw new Error(`[PluginRegistry] Plugin "${e.name}" must have an init() method`);this._plugins.set(e.name,e),this._loadOrder.push(e.name);try{await e.init(this.kernel),this.kernel.events.emit("plugin_loaded",{name:e.name,version:e.version})}catch(t){throw console.error(`[PluginRegistry] Failed to initialize plugin "${e.name}":`,t),this._plugins.delete(e.name),this._loadOrder.pop(),t}return this}remove(e){const t=this._plugins.get(e);if(!t)return!1;if(t.destroy)try{t.destroy()}catch(i){console.error(`[PluginRegistry] Error destroying plugin "${e}":`,i)}this._plugins.delete(e);const s=this._loadOrder.indexOf(e);return s>-1&&this._loadOrder.splice(s,1),this.kernel.events.emit("plugin_unloaded",{name:e}),!0}get(e){return this._plugins.get(e)}has(e){return this._plugins.has(e)}getPluginNames(){return Array.from(this._plugins.keys())}getLoadOrder(){return[...this._loadOrder]}clear(){for(let e=this._loadOrder.length-1;e>=0;e--)this.remove(this._loadOrder[e])}}class O{constructor(e={}){this.width=e.width||800,this.height=e.height||600,this.backgroundColor=e.backgroundColor||"#000000",e.canvas?(this.canvas=e.canvas,this.canvas.width=this.width,this.canvas.height=this.height):(this.canvas=document.createElement("canvas"),this.canvas.width=this.width,this.canvas.height=this.height,(e.parent?typeof e.parent=="string"?document.querySelector(e.parent):e.parent:document.body).appendChild(this.canvas)),this.ctx=this.canvas.getContext("2d")}clear(){this.ctx.fillStyle=this.backgroundColor,this.ctx.fillRect(0,0,this.width,this.height)}resize(e,t){this.width=e,this.height=t,this.canvas.width=e,this.canvas.height=t}}class A{constructor(){this.running=!1,this.lastTime=0,this.callbacks=new Set,this._tick=this._tick.bind(this)}add(e){this.callbacks.add(e)}remove(e){this.callbacks.delete(e)}start(){this.running||(this.running=!0,this.lastTime=performance.now(),requestAnimationFrame(this._tick))}stop(){this.running=!1}_tick(e){if(!this.running)return;const t=(e-this.lastTime)/1e3;this.lastTime=e;const s=Math.min(t,.1);for(const i of this.callbacks)i(s);requestAnimationFrame(this._tick)}}class f{constructor(){this.gameObject=null,this.kernel=null}get physics(){var e;return(e=this.kernel)==null?void 0:e.systems.get("physics")}get input(){var e;return(e=this.kernel)==null?void 0:e.systems.get("input")}get loader(){var e;return(e=this.kernel)==null?void 0:e.systems.get("loader")}get events(){var e;return(e=this.kernel)==null?void 0:e.events}onAttach(){}onDetach(){}update(e){}render(e){}}class B extends f{constructor(e="box",t=50,s=50,i=25){super(),this.type=e,this.width=t,this.height=s,this.radius=i,this.tag=null}onAttach(){super.onAttach(),this.physics&&this.physics.add(this)}onDetach(){super.onDetach(),this.physics&&this.physics.remove(this)}getBounds(){const e=this.gameObject;if(this.type==="box")return{left:e.x-this.width/2,right:e.x+this.width/2,top:e.y-this.height/2,bottom:e.y+this.height/2};if(this.type==="circle")return{x:e.x,y:e.y,radius:this.radius}}}class _{constructor(){this.colliders=[],this.kernel=null}init(e){this.kernel=e}fixedUpdate(e){this.step()}destroy(){this.colliders=[]}add(e){this.colliders.push(e)}remove(e){const t=this.colliders.indexOf(e);t>-1&&this.colliders.splice(t,1)}step(){for(let e=0;e<this.colliders.length;e++)for(let t=e+1;t<this.colliders.length;t++){const s=this.colliders[e],i=this.colliders[t];this._intersects(s,s.getBounds(),i,i.getBounds())&&(this._notifyCollision(s.gameObject,i.gameObject),this._notifyCollision(i.gameObject,s.gameObject))}}_notifyCollision(e,t){!e||!e.components||e.components.forEach(s=>{s.onCollisionEnter&&s.onCollisionEnter(t)})}checkOverlap(e,t){const s=[],i=e.getBounds();for(const n of this.colliders){if(n===e||t&&n.tag!==t)continue;const r=n.getBounds();this._intersects(e,i,n,r)&&s.push(n)}return s}_intersects(e,t,s,i){if(e.type==="box"&&s.type==="box")return t.left<i.right&&t.right>i.left&&t.top<i.bottom&&t.bottom>i.top;if(e.type==="circle"&&s.type==="circle"){const n=t.x-i.x,r=t.y-i.y;return Math.sqrt(n*n+r*r)<t.radius+i.radius}return!1}addBody(e){this.add(e)}removeBody(e){this.remove(e)}checkCollision(e,t){return this._intersects(e,e.getBounds(),t,t.getBounds())}raycast(e,t,s){return null}setGravity(e,t){}}const $=new _;console.warn("[DopamineJS] GlobalPhysics is deprecated. Use kernel.physics instead.");class x{constructor(){this.keys=new Map,this.mouse={x:0,y:0,buttons:new Map},this.kernel=null,this._onKeyDown=this._onKeyDown.bind(this),this._onKeyUp=this._onKeyUp.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseDown=this._onMouseDown.bind(this),this._onMouseUp=this._onMouseUp.bind(this)}init(e){this.kernel=e,window.addEventListener("keydown",this._onKeyDown),window.addEventListener("keyup",this._onKeyUp),window.addEventListener("mousemove",this._onMouseMove),window.addEventListener("mousedown",this._onMouseDown),window.addEventListener("mouseup",this._onMouseUp)}destroy(){window.removeEventListener("keydown",this._onKeyDown),window.removeEventListener("keyup",this._onKeyUp),window.removeEventListener("mousemove",this._onMouseMove),window.removeEventListener("mousedown",this._onMouseDown),window.removeEventListener("mouseup",this._onMouseUp)}_onKeyDown(e){this.keys.set(e.key,!0)}_onKeyUp(e){this.keys.set(e.key,!1)}_onMouseMove(e){this.mouse.x=e.clientX,this.mouse.y=e.clientY}_onMouseDown(e){this.mouse.buttons.set(e.button,!0)}_onMouseUp(e){this.mouse.buttons.set(e.button,!1)}isKeyDown(e){return this.keys.get(e)||!1}isMouseButtonDown(e=0){return this.mouse.buttons.get(e)||!1}}const F=new x;console.warn("[DopamineJS] GlobalInput is deprecated. Use kernel.input instead.");class S{constructor(){this.assets=new Map,this.kernel=null}init(e){this.kernel=e}destroy(){this.assets.clear()}async loadImage(e,t){return new Promise((s,i)=>{const n=new Image;n.onload=()=>{this.assets.set(e,n),s(n)},n.onerror=i,n.src=t})}get(e){return this.assets.get(e)}}const N=new S;console.warn("[DopamineJS] GlobalLoader is deprecated. Use kernel.loader instead.");class D{constructor(e={}){this.config=e,this.events=new m,this.systems=new I(this),this.plugins=new C(this),this._registerCoreSystems(e),this.fixedTimestep=e.fixedTimestep||1/60,this._accumulator=0,this._maxAccumulator=this.fixedTimestep*5}_registerCoreSystems(e){this.systems.register("ticker",new A,{priority:100});const t={width:e.width,height:e.height,backgroundColor:e.backgroundColor,canvas:e.canvas,...e.renderer};this.systems.register("renderer",new O(t),{priority:90}),this.systems.register("input",new x,{priority:80}),this.systems.register("loader",new S,{priority:70}),this.systems.register("physics",new _,{priority:60})}start(){const e=this.systems.get("ticker");e&&(e.add(this._update.bind(this)),e.start()),this.events.emit("kernel_started")}stop(){const e=this.systems.get("ticker");e&&e.stop(),this.events.emit("kernel_stopped")}_update(e){for(this.events.emit(m.Events.TICK,{dt:e}),this._accumulator+=e,this._accumulator>this._maxAccumulator&&(this._accumulator=this._maxAccumulator);this._accumulator>=this.fixedTimestep;)this.events.emit(m.Events.FIXED_UPDATE,{dt:this.fixedTimestep}),this.systems.fixedUpdate(this.fixedTimestep),this._accumulator-=this.fixedTimestep;this.systems.update(e),this.events.emit(m.Events.RENDER,{dt:e})}get physics(){return this.systems.get("physics")}get input(){return this.systems.get("input")}get loader(){return this.systems.get("loader")}get renderer(){return this.systems.get("renderer")}get ticker(){return this.systems.get("ticker")}destroy(){this.stop(),this.plugins.clear(),this.systems.clear(),this.events.clear()}}const v={init(a){},update(a){},fixedUpdate(a){},destroy(){}};class K{constructor(){this.kernel=null}init(e){this.kernel=e}update(e){}fixedUpdate(e){}destroy(){}}const X={...v,addBody(a){},removeBody(a){},checkCollision(a,e){},raycast(a,e,t){},setGravity(a,e){},step(a){}},H={...v,registerSound(a,e){},preloadSounds(a){},play(a,e){},playTone(a,e,t,s){},stop(a){},toggleMute(){},setVolume(a){}},q={...v,registerSprite(a,e){},registerEffect(a,e){},play(a,e,t,...s){},emit(a){},clear(){},confetti(a,e,t){},coinShower(a,e,t){},sparkle(a,e,t,s){},fire(a,e,t){},starBurst(a,e,t){}};class W{constructor(){this.gameObjects=[],this.kernel=null}onEnter(){}onExit(){}add(e){return this.kernel&&(e.kernel=this.kernel),this.gameObjects.push(e),e}remove(e){const t=this.gameObjects.indexOf(e);t>-1&&this.gameObjects.splice(t,1)}update(e){for(const t of this.gameObjects)t.update(e)}render(e){for(const t of this.gameObjects)t.render(e)}}class L{constructor(e){this.game=e,this.currentScene=null}run(e){this.currentScene&&this.currentScene.onExit(),this.currentScene=e,this.currentScene.game=this.game,this.game.scene=e,e.onEnter()}}class J{constructor(e={}){this.config=e,this.kernel=new D(e),this.director=new L(this),this.kernel.systems.register("director",this.director),this.kernel.events.on(m.Events.TICK,this._update.bind(this),10),this.kernel.events.on(m.Events.RENDER,this._render.bind(this),10)}get renderer(){return this.kernel.renderer}get ticker(){return this.kernel.ticker}get physics(){return this.kernel.physics}get input(){return this.kernel.input}start(){this.kernel.start()}stop(){this.kernel.stop()}setScene(e){e.kernel=this.kernel,this.director.run(e)}_update({dt:e}){this.director.currentScene&&this.director.currentScene.update(e)}_render({dt:e}){this.renderer.clear(),this.director.currentScene&&this.director.currentScene.render(this.renderer.ctx)}destroy(){this.kernel.destroy()}}class Y{constructor(e=0,t=0){this.x=e,this.y=t,this.rotation=0,this.scale={x:1,y:1},this.components=[],this.children=[],this.parent=null,this._kernel=null}get kernel(){return this._kernel}set kernel(e){this._kernel=e;for(const t of this.components)t.kernel=e;for(const t of this.children)t.kernel=e}addChild(e){return e.parent=this,e.kernel=this.kernel,this.children.push(e),e}addComponent(e){return e.gameObject=this,e.kernel=this.kernel,this.components.push(e),e.onAttach(),e}getComponent(e){return this.components.find(t=>t instanceof e)}update(e){for(const t of this.components)t.update&&t.update(e);for(const t of this.children)t.update(e)}render(e){e.save(),e.translate(this.x,this.y),e.rotate(this.rotation),e.scale(this.scale.x,this.scale.y);for(const t of this.components)t.render&&t.render(e);for(const t of this.children)t.render(e);e.restore()}}class k{constructor(e=0,t=0){this.x=e,this.y=t}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}scale(e){return this.x*=e,this.y*=e,this}distance(e){const t=this.x-e.x,s=this.y-e.y;return Math.sqrt(t*t+s*s)}normalize(){const e=Math.sqrt(this.x*this.x+this.y*this.y);return e>0&&(this.x/=e,this.y/=e),this}clone(){return new k(this.x,this.y)}static distance(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}}class U extends f{constructor(e){super(),this.image=e,this.anchor={x:.5,y:.5},this.width=e?e.width:0,this.height=e?e.height:0,this.frame={x:0,y:0,w:this.width,h:this.height}}setFrame(e,t,s,i){this.frame={x:e,y:t,w:s,h:i},this.width=s,this.height=i}setTexture(e){this.image=e,e&&this.setFrame(0,0,e.width,e.height)}render(e){if(!this.image)return;const t=this.frame.w,s=this.frame.h,i=-t*this.anchor.x,n=-s*this.anchor.y;e.drawImage(this.image,this.frame.x,this.frame.y,t,s,i,n,t,s)}}class V extends f{constructor(){super(),this.animations={},this.currentAnim=null,this.timer=0,this.currentFrameIndex=0,this.sprite=null}onAttach(){this.sprite=this.gameObject.getComponent(U),this.sprite||console.warn("Animator attached to GameObject without a Sprite component.")}addAnimation(e,t,s=10,i=!0){this.animations[e]={frames:t,fps:s,loop:i}}play(e){this.currentAnim&&this.currentAnim.name===e||this.animations[e]&&(this.currentAnim={name:e,...this.animations[e]},this.currentFrameIndex=0,this.timer=0,this._updateFrame())}update(e){if(!this.currentAnim||!this.sprite)return;this.timer+=e;const t=1/this.currentAnim.fps;this.timer>=t&&(this.timer-=t,this.currentFrameIndex++,this.currentFrameIndex>=this.currentAnim.frames.length&&(this.currentAnim.loop?this.currentFrameIndex=0:this.currentFrameIndex=this.currentAnim.frames.length-1),this._updateFrame())}_updateFrame(){const e=this.currentAnim.frames[this.currentFrameIndex];this.sprite.setFrame(e.x,e.y,e.w,e.h)}}class Q{static createGround(e,t,s="#333"){const i=document.createElement("canvas");i.width=e,i.height=t;const n=i.getContext("2d");n.fillStyle=s,n.fillRect(0,0,e,t);for(let r=0;r<1e3;r++){n.fillStyle=Math.random()>.5?"#444":"#222";const h=Math.random()*4+2;n.fillRect(Math.random()*e,Math.random()*t,h,h)}n.strokeStyle="rgba(255,255,255,0.05)",n.lineWidth=2,n.beginPath();for(let r=0;r<=e;r+=64)n.moveTo(r,0),n.lineTo(r,t);for(let r=0;r<=t;r+=64)n.moveTo(0,r),n.lineTo(e,r);return n.stroke(),i}static createCharacterSheet(e,t){const n=document.createElement("canvas");n.width=64*4,n.height=64;const r=n.getContext("2d");for(let h=0;h<4;h++){const c=h*64,l=0,u=c+64/2,y=l+64/2,p=h%2===0?0:-2,w=h===1?5:h===3?-5:0;r.fillStyle=e,r.beginPath(),r.arc(u,y+p,20,0,Math.PI*2),r.fill(),r.fillStyle=t,r.beginPath(),r.arc(u-15,y+p+w,8,0,Math.PI*2),r.arc(u+15,y+p-w,8,0,Math.PI*2),r.fill(),r.fillStyle=Z(e),r.beginPath(),r.arc(u,y+p,15,0,Math.PI*2),r.fill(),t==="#333"&&(r.fillStyle="#000",r.fillRect(u+10,y+p-5,25,6))}return n}}function Z(a,e){return a}class ee extends f{constructor(e){super(),this.system=e}play(e,t={}){const s=this.gameObject.x,i=this.gameObject.y;switch(e){case"confetti":this.system.confetti(s,i,t.count);break;case"fire":this.system.fire(s,i,t.count);break;case"sparkle":this.system.sparkle(s,i,t.count,t.color);break;case"blood":this.system.emit({x:s,y:i,count:10,color:["#8a0303","#ff0000"],speed:4,gravity:.1,decay:.05});break;default:this.system.emit({x:s,y:i,...t})}}}class te extends f{constructor(){super(),this.intensity=0,this.duration=0,this.timer=0,this.originalPos={x:0,y:0},this.isShaking=!1}shake(e=5,t=.2){this.intensity=e,this.duration=t,this.timer=0,this.isShaking=!0,this.timer===0&&(this.originalPos.x=this.gameObject.x,this.originalPos.y=this.gameObject.y)}update(e){if(!this.isShaking)return;if(this.timer+=e,this.timer>=this.duration){this.isShaking=!1,this.gameObject.x=this.originalPos.x,this.gameObject.y=this.originalPos.y;return}const t=(Math.random()-.5)*2*this.intensity,s=(Math.random()-.5)*2*this.intensity;this.gameObject.x=this.originalPos.x+t,this.gameObject.y=this.originalPos.y+s}}o.Animator=V,o.Collider=B,o.Component=f,o.DataService=M,o.Director=L,o.DopamineKernel=D,o.EventBus=m,o.Game=J,o.GameObject=Y,o.GameUI=P,o.GlobalInput=F,o.GlobalLoader=N,o.GlobalPhysics=$,o.IAudioSystem=H,o.IParticleSystem=q,o.IPhysicsSystem=X,o.ISystem=v,o.Input=x,o.Loader=S,o.ParticleEmitter=ee,o.ParticleSystem=E,o.Physics=_,o.PluginRegistry=C,o.Renderer=O,o.RewardSystem=b,o.Scene=W,o.ScreenShake=te,o.SoundManager=T,o.Sprite=U,o.System=K,o.SystemRegistry=I,o.TextureGenerator=Q,o.Ticker=A,o.Vector2=k,o.default=G,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dopaminejs",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Lightweight Game Feel Engine - Add juice, rewards, and feedback to HTML5 games",
5
5
  "type": "module",
6
6
  "main": "./dist/dopamine.umd.cjs",
@@ -43,7 +43,14 @@ export class DopamineKernel {
43
43
  });
44
44
 
45
45
  // Renderer
46
- this.systems.register('renderer', new Renderer(config.renderer || {}), {
46
+ const rendererOptions = {
47
+ width: config.width,
48
+ height: config.height,
49
+ backgroundColor: config.backgroundColor,
50
+ canvas: config.canvas,
51
+ ...config.renderer
52
+ };
53
+ this.systems.register('renderer', new Renderer(rendererOptions), {
47
54
  priority: 90
48
55
  });
49
56
 
package/src/core/Game.js CHANGED
@@ -16,6 +16,7 @@ export class Game {
16
16
 
17
17
  // Initialize Director
18
18
  this.director = new Director(this);
19
+ this.kernel.systems.register('director', this.director);
19
20
 
20
21
  // Bind to kernel tick event for scene updates
21
22
  this.kernel.events.on(EventBus.Events.TICK, this._update.bind(this), 10);
@@ -14,7 +14,23 @@ export class GameObject {
14
14
  this.components = [];
15
15
  this.children = [];
16
16
  this.parent = null;
17
- this.kernel = null; // Injected by Scene or Game
17
+ this._kernel = null;
18
+ }
19
+
20
+ get kernel() {
21
+ return this._kernel;
22
+ }
23
+
24
+ set kernel(value) {
25
+ this._kernel = value;
26
+ // Propagate to components
27
+ for (const comp of this.components) {
28
+ comp.kernel = value;
29
+ }
30
+ // Propagate to children
31
+ for (const child of this.children) {
32
+ child.kernel = value;
33
+ }
18
34
  }
19
35
 
20
36
  /**
@@ -60,7 +60,7 @@ export class PluginRegistry {
60
60
  version: plugin.version
61
61
  });
62
62
 
63
- console.log(`[PluginRegistry] Loaded plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ''}`);
63
+ // Plugin loaded successfully
64
64
  } catch (error) {
65
65
  console.error(`[PluginRegistry] Failed to initialize plugin "${plugin.name}":`, error);
66
66
  this._plugins.delete(plugin.name);
@@ -106,7 +106,7 @@ export class PluginRegistry {
106
106
  version: plugin.version
107
107
  });
108
108
 
109
- console.log(`[PluginRegistry] Loaded plugin: ${plugin.name}${plugin.version ? ` v${plugin.version}` : ''}`);
109
+ // Plugin loaded successfully
110
110
  } catch (error) {
111
111
  console.error(`[PluginRegistry] Failed to initialize plugin "${plugin.name}":`, error);
112
112
  this._plugins.delete(plugin.name);
package/src/core/Scene.js CHANGED
@@ -3,8 +3,8 @@
3
3
  */
4
4
  export class Scene {
5
5
  constructor() {
6
- this.children = [];
7
- this.game = null;
6
+ this.gameObjects = [];
7
+ this.kernel = null; // Injected by Game
8
8
  }
9
9
 
10
10
  /**
@@ -12,30 +12,19 @@ export class Scene {
12
12
  */
13
13
  onEnter() { }
14
14
 
15
- onExit() { }
16
-
17
15
  /**
18
- * Update loop for the scene.
19
- * @param {number} dt
16
+ * Called when the scene is removed from the Game.
20
17
  */
21
- update(dt) {
22
- // Update all children (GameObjects)
23
- for (const child of this.children) {
24
- if (child.update) child.update(dt);
25
- }
26
- }
27
-
28
- /**
29
- this.gameObjects = [];
30
- this.kernel = null; // Injected by Game
31
- }
18
+ onExit() { }
32
19
 
33
20
  /**
34
21
  * Add a GameObject to the scene.
35
22
  * @param {GameObject} gameObject
36
23
  */
37
24
  add(gameObject) {
38
- gameObject.kernel = this.kernel; // Inject kernel
25
+ if (this.kernel) {
26
+ gameObject.kernel = this.kernel; // Inject kernel
27
+ }
39
28
  this.gameObjects.push(gameObject);
40
29
  return gameObject;
41
30
  }
@@ -51,12 +40,20 @@ export class Scene {
51
40
  }
52
41
  }
53
42
 
43
+ /**
44
+ * Update loop for the scene.
45
+ * @param {number} dt
46
+ */
54
47
  update(dt) {
55
48
  for (const obj of this.gameObjects) {
56
49
  obj.update(dt);
57
50
  }
58
51
  }
59
52
 
53
+ /**
54
+ * Render loop for the scene.
55
+ * @param {CanvasRenderingContext2D} ctx
56
+ */
60
57
  render(ctx) {
61
58
  for (const obj of this.gameObjects) {
62
59
  obj.render(ctx);
@@ -28,14 +28,11 @@ export class WebGLParticleSystem {
28
28
  this.registeredEffects = new Map();
29
29
  }
30
30
 
31
- // ISystem interface
32
31
  init(kernel) {
33
32
  this.kernel = kernel;
34
33
  this._initWebGL();
35
34
  this._createShaders();
36
35
  this._createBuffers();
37
-
38
- console.log('[WebGLParticles] Initialized with max particles:', this.maxParticles);
39
36
  }
40
37
 
41
38
  update(dt) {
@@ -24,7 +24,6 @@ export default class Dopamine {
24
24
 
25
25
  async init() {
26
26
  await this.rewardSystem.init();
27
- console.log('DopamineJS Initialized 🚀');
28
27
  return {
29
28
  rewardSystem: this.rewardSystem,
30
29
  gameUI: this.gameUI,
@@ -7,17 +7,25 @@ export class Renderer {
7
7
  this.height = options.height || 600;
8
8
  this.backgroundColor = options.backgroundColor || '#000000';
9
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');
10
+ // Use existing canvas if provided, otherwise create new one
11
+ if (options.canvas) {
12
+ this.canvas = options.canvas;
13
+ this.canvas.width = this.width;
14
+ this.canvas.height = this.height;
15
+ } else {
16
+ this.canvas = document.createElement('canvas');
17
+ this.canvas.width = this.width;
18
+ this.canvas.height = this.height;
19
+
20
+ // Append to body or specified container
21
+ const parent = options.parent ?
22
+ (typeof options.parent === 'string' ? document.querySelector(options.parent) : options.parent)
23
+ : document.body;
14
24
 
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;
25
+ parent.appendChild(this.canvas);
26
+ }
19
27
 
20
- parent.appendChild(this.canvas);
28
+ this.ctx = this.canvas.getContext('2d');
21
29
  }
22
30
 
23
31
  /**