Le luci da palco dell'Ingorgo: fasci colorati che spazzano dalle teste mobili, bagliore a tempo, strobo, laser verdi alla tecno di Cambray Digny, palla a specchi all'underground; solo alla festa (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9Quo9nEdXyjXYF8ma
This commit is contained in:
@@ -487,6 +487,81 @@ export const EFFECTS = {
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
},
|
||||
// Le luci da palco dell'Ingorgo (Andrea, 30 ottobre): dalle teste mobili (`from`) i fasci colorati che spazzano il
|
||||
// cielo; sul palco un bagliore che pulsa a tempo (`bpm`) e cambia colore a ogni battuta; ogni tanto lo strobo.
|
||||
stagelights(ctx, e, time) {
|
||||
const colors = e.colors ?? ['255,60,200', '60,220,255', '120,255,90', '255,190,40'], beat = time / (60000 / (e.bpm ?? 124));
|
||||
const hit = 1 - (beat % 1), bar = Math.floor(beat / 4);
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'lighter';
|
||||
if (e.wash) {
|
||||
const [x, y, r] = e.wash, c = colors[bar % colors.length];
|
||||
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
|
||||
g.addColorStop(0, `rgba(${c},${0.1 + 0.18 * hit ** 2})`);
|
||||
g.addColorStop(1, `rgba(${c},0)`);
|
||||
ctx.fillStyle = g;
|
||||
ctx.fillRect(x - r, y - r, r * 2, r * 2);
|
||||
}
|
||||
for (const [k, [x, y]] of (e.from ?? []).entries()) {
|
||||
for (let i = 0; i < (e.beams ?? 2); i++) {
|
||||
const n = k * 3 + i, swing = Math.sin(time / (900 + n * 170) + n * 1.9) * (e.spread ?? 0.75);
|
||||
const a = -Math.PI / 2 + swing + (k % 2 ? 0.25 : -0.25), len = e.len ?? 260, half = 0.045;
|
||||
const c = colors[(n + bar) % colors.length], tipX = x + Math.cos(a) * len, tipY = y + Math.sin(a) * len;
|
||||
const g = ctx.createLinearGradient(x, y, tipX, tipY);
|
||||
g.addColorStop(0, `rgba(${c},0.32)`);
|
||||
g.addColorStop(1, `rgba(${c},0)`);
|
||||
ctx.fillStyle = g;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + Math.cos(a - half) * len, y + Math.sin(a - half) * len);
|
||||
ctx.lineTo(x + Math.cos(a + half) * len, y + Math.sin(a + half) * len);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.fillStyle = `rgba(${c},0.9)`;
|
||||
ctx.fillRect(Math.round(x) - 1, Math.round(y) - 1, 3, 3);
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
// Lo strobo: un lampo bianco brevissimo ogni `strobe` battute.
|
||||
if (e.strobe && Math.floor(beat) % e.strobe === 0 && beat % 1 < 0.12) {
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.13)';
|
||||
ctx.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
}
|
||||
},
|
||||
// I laser della tecno: righe sottili verdi (o del colore dato) che si aprono a ventaglio e si richiudono.
|
||||
lasers(ctx, e, time) {
|
||||
const [x, y] = e.at, n = e.count ?? 7, open = 0.35 + 0.35 * Math.sin(time / 1300), tilt = Math.sin(time / 2100) * 0.4;
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'lighter';
|
||||
ctx.strokeStyle = `rgba(${e.color ?? '90,255,110'},${0.35 + 0.2 * Math.sin(time / 90) ** 2})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
for (let i = 0; i < n; i++) {
|
||||
const a = -Math.PI / 2 + tilt + (i / (n - 1) - 0.5) * 2 * open * 1.4;
|
||||
ctx.moveTo(x + 0.5, y + 0.5);
|
||||
ctx.lineTo(x + Math.cos(a) * (e.len ?? 400), y + Math.sin(a) * (e.len ?? 400));
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
},
|
||||
// La palla a specchi: puntini di luce che girano sui muri intorno (`area`), più chiari vicino alla palla.
|
||||
mirrorball(ctx, e, time) {
|
||||
const [bx, by] = e.at, [ax, ay, aw, ah] = e.area, turn = time / 4200;
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = 'lighter';
|
||||
for (let i = 0; i < (e.count ?? 40); i++) {
|
||||
const u = (hash(i * 13) + turn) % 1, x = ax + Math.round(u * aw), y = ay + Math.round(hash(i * 7 + 3) * ah);
|
||||
const glint = 0.5 + 0.5 * Math.sin(time / 160 + i * 2.3);
|
||||
ctx.fillStyle = `rgba(${e.color ?? '220,200,255'},${0.35 + 0.5 * glint})`;
|
||||
ctx.fillRect(x, y, 2, 2);
|
||||
}
|
||||
const g = ctx.createRadialGradient(bx, by, 0, bx, by, 9);
|
||||
g.addColorStop(0, 'rgba(255,255,255,0.8)');
|
||||
g.addColorStop(1, 'rgba(200,180,255,0)');
|
||||
ctx.fillStyle = g;
|
||||
ctx.fillRect(bx - 9, by - 9, 18, 18);
|
||||
ctx.restore();
|
||||
},
|
||||
// Lampioni: un alone caldo che si accende (di solito solo di sera, con `phase`).
|
||||
lamps(ctx, e, time) {
|
||||
ctx.save();
|
||||
|
||||
Reference in New Issue
Block a user