"use strict"; const DeflectionSparksFx = (function(){ const DeflectionSparksFx = function(xgravity){ let sparks = []; this.add = (cell_x, cell_y, normal_x, normal_y, intensity = 1.0) => { const base_count = Math.floor(10 + (intensity * 25)); const count = Math.min(60, base_count); const base_angle = Math.atan2(normal_y, normal_x); for(let i = 0; i < count; i++){ const spread = (Math.random() - 0.5) * (Math.PI * 0.7); const spark_angle = base_angle + spread; const speed = (Math.random() * 12 + 6) * Math.min(2.5, intensity); const life = (Math.random() * 0.18) + 0.08; sparks.push({ x : cell_x, y : cell_y, vx : Math.cos(spark_angle) * speed, vy : Math.sin(spark_angle) * speed, len : (Math.random() * 0.3) + 0.15, life : life, max_life : life, color : Math.random() > 0.3 ? "#fef08a" : "#f97316" }); } }; this.update = (delta_time) => { for(let i = sparks.length - 1; i >= 0; i--){ const s = sparks[i]; s.life -= delta_time; if(s.life <= 0){ sparks.splice(i, 1); continue; } s.x += s.vx * delta_time; s.y += s.vy * delta_time; s.vx *= 0.90; s.vy *= 0.90; } }; this.render = (ctx, cell_px, cx, cy) => { for(let i = 0; i < sparks.length; i++){ const s = sparks[i]; const px = cx + (s.x * cell_px); const py = cy + (s.y * cell_px); const progress = Math.max(0, s.life / s.max_life); const spd = Math.sqrt(s.vx * s.vx + s.vy * s.vy); const dir_x = spd > 0.001 ? s.vx / spd : 0; const dir_y = spd > 0.001 ? s.vy / spd : 0; const tail_length_px = (s.len || 0.25) * cell_px * Math.min(2.5, spd * 0.15); ctx.lineWidth = cell_px * 0.06; ctx.strokeStyle = s.color; ctx.globalAlpha = progress; ctx.beginPath(); ctx.moveTo(px, py); ctx.lineTo(px - (dir_x * tail_length_px), py - (dir_y * tail_length_px)); ctx.stroke(); } }; this.reset = () => { sparks = []; }; }; return DeflectionSparksFx; })();