(function () { // ============================================================ // CONFIG (YA AJUSTADO A LO QUE ME DIJISTE) // ============================================================ var P5_SRC = "/wp-content/uploads/fireworks/lib/p5.min.js"; var P5_SOUND_SRC = "/wp-content/uploads/fireworks/lib/p5.sound.min.js";// Audios (Media Library) var BOOM_BASE = "/wp-content/uploads/2025/12/"; var boomFiles = [ BOOM_BASE + "boom1.mp3", BOOM_BASE + "boom2.mp3", BOOM_BASE + "boom3.mp3", BOOM_BASE + "boom4.mp3", BOOM_BASE + "boom5.mp3" ];// Debe existir en la página (YOOtheme Builder -> HTML element) //
var HOST_ID = "fireworks-wrap"; // ============================================================function loadScript(src) { return new Promise(function (resolve, reject) { var s = document.createElement("script"); s.src = src; s.defer = true; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); }); }function boot() { var host = document.getElementById(HOST_ID); if (!host) return; // no estamos en la página del fireworks if (host.dataset.fireworksMounted === "1") return; host.dataset.fireworksMounted = "1";// Cargar p5 y p5.sound SOLO si hace falta var chain = Promise.resolve(); if (!window.p5) chain = chain.then(function () { return loadScript(P5_SRC); }); chain = chain.then(function () { // Evita duplicar p5.sound si ya está if (window.p5 && window.p5.SoundFile) return; return loadScript(P5_SOUND_SRC); });chain.then(function () { startSketch(host); }).catch(function (e) { console.error("Fireworks: no se pudieron cargar p5/p5.sound", e); }); }function startSketch(host) { new window.p5(function (p) { var particles = []; var mode = 1; // 1 attract, 2 repel var paused = false;// HUD font (system) var HUD_FONT = "system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif";// Audio var booms = new Array(boomFiles.length).fill(null); var boomBag = []; var boomBagPos = 0; var lastBoomIndex = -1; var audioReadyCount = 0; var audioErrorCount = 0;// ---------- Audio helpers ---------- function rebuildBoomBag() { var valid = []; for (var i = 0; i < booms.length; i++) if (booms[i]) valid.push(i);boomBag = valid; p.shuffle(boomBag, true); boomBagPos = 0;// Evitar que el primero sea el mismo del último if (boomBag.length > 1 && boomBag[0] === lastBoomIndex) { var swapWith = p.int(p.random(1, boomBag.length)); var tmp = boomBag[0]; boomBag[0] = boomBag[swapWith]; boomBag[swapWith] = tmp; } }function nextBoomIndex() { if (!boomBag || boomBag.length === 0) return -1; if (boomBagPos >= boomBag.length) { rebuildBoomBag(); if (boomBag.length === 0) return -1; } return boomBag[boomBagPos++]; }function loadBoomsAsync() { if (typeof p.loadSound !== "function") return;p.soundFormats("mp3", "wav", "aif", "aiff"); audioReadyCount = 0; audioErrorCount = 0;boomFiles.forEach(function (file, i) { p.loadSound( file, function (snd) { booms[i] = snd; audioReadyCount++; rebuildBoomBag(); }, function (err) { console.error("Fireworks: audio load error:", file, err); audioErrorCount++; } ); }); }function playBoom(mx) { var idx = nextBoomIndex(); if (idx < 0 || !booms[idx]) return;var s = booms[idx];// Variaciones suaves para no sonar monótono var rate = p.random(0.92, 1.08); var amp = p.random(0.75, 0.95); var pan = p.map(mx, 0, p.width, -1, 1);s.stop(); s.rate(rate); s.setVolume(amp); s.pan(pan); s.play();lastBoomIndex = idx; }// ---------- Particles ---------- function Particle(x, y) { this.pos = p.createVector(x, y); this.prev = this.pos.copy(); this.vel = window.p5.Vector.random2D().mult(p.random(0.2, 2.2)); this.acc = p.createVector(0, 0); this.life = p.int(p.random(120, 260));this.hue = p.random(0, 360); this.sat = p.random(60, 100); this.bri = 100;this.maxSpeed = 10; this.gravity = 0.0; }Particle.prototype.applyForce = function (f) { this.acc.add(f); };Particle.prototype.attract = function (target) { var dir = window.p5.Vector.sub(target, this.pos); var d = p.constrain(dir.mag(), 20, 220); dir.normalize(); this.applyForce(dir.mult(2.0 / d)); };Particle.prototype.repel = function (target) { var dir = window.p5.Vector.sub(this.pos, target); var d = p.constrain(dir.mag(), 20, 220); dir.normalize(); this.applyForce(dir.mult(2.2 / d)); };Particle.prototype.update = function () { this.prev.set(this.pos);if (this.gravity > 0) this.applyForce(p.createVector(0, this.gravity));this.vel.add(this.acc); this.vel.limit(this.maxSpeed); this.pos.add(this.vel); this.acc.mult(0);if (this.pos.x < 0 || this.pos.x > p.width) this.vel.x *= -0.90; if (this.pos.y < 0 || this.pos.y > p.height) this.vel.y *= -0.90;this.pos.x = p.constrain(this.pos.x, 0, p.width); this.pos.y = p.constrain(this.pos.y, 0, p.height);this.vel.mult(0.992); this.life--; };Particle.prototype.display = function () { var alpha = p.map(this.life, 0, 260, 0, 255); var speed = this.vel.mag();// Trail p.stroke(this.hue, this.sat, this.bri, alpha); p.strokeWeight(p.map(speed, 0, this.maxSpeed, 0.6, 2.6)); p.line(this.prev.x, this.prev.y, this.pos.x, this.pos.y);// Core p.noStroke(); p.fill(this.hue, this.sat, this.bri, alpha); p.circle(this.pos.x, this.pos.y, p.map(speed, 0, this.maxSpeed, 2, 6)); };function spawnExplosion(x, y) { var fireworkHue = p.random(0, 360); for (var i = 0; i < 160; i++) { var part = new Particle(x, y); part.vel = window.p5.Vector.random2D().mult(p.random(2.0, 8.0)); part.life = p.int(p.random(70, 170)); part.hue = fireworkHue + p.random(-18, 18); part.sat = p.random(80, 100); part.bri = 100; part.gravity = p.random(0.02, 0.08); particles.push(part); } }// ---------- Drawing ---------- function fitToHost() { var w = Math.max(1, host.clientWidth); var h = Math.max(1, host.clientHeight); p.resizeCanvas(w, h); }function drawHappyNewYear() { var s = Math.min(p.width, p.height); var textSizePx = p.constrain(s * 0.14, 48, 120); var leadingPx = textSizePx * 0.95;p.textAlign(p.CENTER, p.CENTER); p.textFont("Oswald"); // usa Google Font si está cargada, si no cae al fallback del navegador p.textStyle(p.BOLD); p.textSize(textSizePx); p.textLeading(leadingPx);// Blanco con alpha (HSB) p.fill(0, 0, 100, 90); p.text("Happy\nNew\nYear", p.width / 2, p.height / 2); }function drawHUD() { var hud = "Particles: " + particles.length + " | Mode: " + (mode === 1 ? "ATTRACT (1)" : "REPEL (2)") + " | Drag: spawn | Click: fireworks | Audio: " + audioReadyCount + "/" + boomFiles.length;var fs = (p.width < 520) ? 11 : 13;p.textFont(HUD_FONT); p.textStyle(p.NORMAL); p.textSize(fs); p.textAlign(p.CENTER, p.BASELINE);var y = p.height - 18; var w = Math.min(p.width - 20, p.textWidth(hud) + 36);// pill background p.noStroke(); p.fill(0, 0, 0, 140); p.rectMode(p.CENTER); p.rect(p.width / 2, y - 6, w, 28, 16);p.fill(0, 0, 100, 230); p.text(hud, p.width / 2, y);if (audioErrorCount > 0) { p.textSize(Math.max(10, fs - 2)); p.fill(0, 0, 100, 170); p.text("Audio errors: " + audioErrorCount, p.width / 2, y - 28); }p.rectMode(p.CORNER); }// ---------- p5 lifecycle ---------- p.setup = function () { var c = p.createCanvas(1, 1); c.parent(host);p.pixelDensity(window.devicePixelRatio || 1); p.colorMode(p.HSB, 360, 100, 100, 255); p.background(0);// Seed inicial for (var i = 0; i < 250; i++) { particles.push(new Particle(p.random(p.width), p.random(p.height))); }fitToHost(); requestAnimationFrame(fitToHost); setTimeout(fitToHost, 250);loadBoomsAsync(); rebuildBoomBag(); };p.draw = function () { if (paused) { drawHUD(); return; }// Fade suave p.noStroke(); p.fill(0, 0, 0, 22); p.rect(0, 0, p.width, p.height);// Texto debajo drawHappyNewYear();// Partículas encima con glow (ADD) p.blendMode(p.ADD);var mouse = p.createVector(p.mouseX, p.mouseY); for (var i = particles.length - 1; i >= 0; i--) { var part = particles[i];if (mode === 1) part.attract(mouse); else part.repel(mouse);part.update(); part.display();if (part.life <= 0) particles.splice(i, 1); }p.blendMode(p.BLEND);// Mantener un mínimo while (particles.length < 250) { particles.push(new Particle(p.random(p.width), p.random(p.height))); }drawHUD(); };p.mousePressed = function () { // Audio en web: debe activarse por gesto del usuario if (typeof p.userStartAudio === "function") p.userStartAudio();playBoom(p.mouseX); spawnExplosion(p.mouseX, p.mouseY); };p.mouseDragged = function () { for (var i = 0; i < 8; i++) { var part = new Particle(p.mouseX + p.random(-8, 8), p.mouseY + p.random(-8, 8)); part.hue = p.random(0, 360); part.sat = 85; part.bri = 100; particles.push(part); } };p.keyPressed = function () { if (p.key === "1") mode = 1; if (p.key === "2") mode = 2;if (p.key === "p" || p.key === "P") paused = !paused;if (p.key === "c" || p.key === "C") { particles = []; p.background(0); } };// Responsive al tamaño del contenedor try { var ro = new ResizeObserver(function () { fitToHost(); }); ro.observe(host); } catch (e) { // fallback si no hay ResizeObserver window.addEventListener("resize", fitToHost); }}, host); }// Run if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", boot); } else { boot(); } })();
Skip to main content

Stories

Our latest impressions and news