diff --git a/index.html b/index.html
index 24a5f11..3ddb21d 100644
--- a/index.html
+++ b/index.html
@@ -251,6 +251,69 @@
animation: levelUpAnim 1.5s forwards;
}
+ .wipe {
+ /* A full‑screen coloured overlay that slides across */
+ position: fixed;
+ inset: 0;
+ background: var(--wipe-color);
+ mix-blend-mode: screen; /* keep the glitch/scanline look */
+ animation: wipeAnim 0.8s ease-out forwards;
+ pointer-events: none;
+ z-index: 150; /* above .bg-effect but below UI */
+ }
+
+ /* Wipe moves from left → right */
+ @keyframes wipeAnim {
+ 0% { transform: translateX(-100%); }
+ 100% { transform: translateX(100%); }
+ }
+
+ /* ------------------------------------------------------------------ */
+ /* 2️⃣ Define a palette of 10 neon colours (CSS custom properties) */
+ /* ------------------------------------------------------------------ */
+ :root {
+ /* existing vars … */
+ --neon-0: #c266c2; /* muted magenta */
+ --neon-1: #66c2c2; /* muted cyan */
+ --neon-2: #c26633; /* muted orange‑red */
+ --neon-3: #66c266; /* muted chartreuse */
+ --neon-4: #c2668a; /* muted deep pink */
+ --neon-5: #66c28a; /* muted spring green */
+ --neon-6: #c28533; /* muted dark orange */
+ --neon-7: #6688c2; /* muted deep sky blue */
+ --neon-8: #c266a0; /* muted hot pink */
+ --neon-9: #66c266; /* muted lawn green */
+ }
+
+ /* --------------------------------------------------------------
+ Digital Rain (Matrix‑style) – sits above .bg-effect, below UI
+ -------------------------------------------------------------- */
+ .digital-rain {
+ position: fixed;
+ inset: 0;
+ pointer-events: none;
+ z-index: 0;
+ background: transparent;
+ }
+
+ /* Glitch flash that appears when wind changes */
+ body.glitch-flash::after {
+ content: "";
+ position: fixed;
+ inset: 0;
+ background: rgba(255,255,255,0.3);
+ mix-blend-mode: screen;
+ pointer-events: none;
+ animation: glitchFlash 0.3s forwards;
+ }
+
+ /* Flash animation */
+ @keyframes glitchFlash {
+ 0% { opacity: 0; }
+ 50% { opacity: 1; }
+ 100% { opacity: 0; }
+ }
+
@@ -260,6 +323,8 @@
+
+
Level Up!
@@ -607,44 +672,156 @@
}
}
+ // 10‑colour neon palette (same order as the CSS vars above)
+ const NEON_PALETTE = [
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-0').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-1').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-2').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-3').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-4').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-5').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-6').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-7').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-8').trim(),
+ getComputedStyle(document.documentElement).getPropertyValue('--neon-9').trim(),
+ ];
+
function levelUp() {
level++;
-
- // Increase Speed (Decrease interval)
- // Cap at minimum 100ms
dropInterval = Math.max(100, 1000 - (level * 120));
-
- // Visual feedback on UI
document.getElementById('level-value').innerText = level;
-
- // Flash border effect
+
+ // Flash border (unchanged)
const container = document.getElementById('game-container');
container.style.borderColor = '#fff';
- setTimeout(() => {
- container.style.borderColor = '#333';
- }, 200);
+ setTimeout(() => container.style.borderColor = '#333', 200);
playSFX('sfx-levelUp');
-
- // *** advance to next music track ***
nextTrack();
- // ----- NEW: show “Level Up!” animation -----
+ // ----- NEW: Level‑Up “Level Up!” overlay (unchanged) -----
const overlay = document.getElementById('level-up-overlay');
- overlay.classList.remove('active'); // reset (in case it’s still there)
- // Force reflow so the removal takes effect
+ overlay.classList.remove('active');
void overlay.offsetWidth;
overlay.classList.add('active');
-
- // Remove the class after the animation finishes (1.5 s)
setTimeout(() => overlay.classList.remove('active'), 1500);
+
+ /* -------------------------------------------------------------
+ * NEW SECTION – background colour change + wipe effect
+ * ------------------------------------------------------------- */
+ // 1️⃣ Pick a random neon colour
+ const newColor = NEON_PALETTE[Math.floor(Math.random() * NEON_PALETTE.length)];
+
+ // 2️⃣ Apply it to the .bg-effect element (the base background)
+ const bg = document.querySelector('.bg-effect');
+ bg.style.background = newColor;
+
+ // 3️⃣ Create a temporary wipe overlay
+ const wipe = document.createElement('div');
+ wipe.className = 'wipe';
+ // expose the colour to the CSS animation via a custom property
+ wipe.style.setProperty('--wipe-color', newColor);
+ document.body.appendChild(wipe);
+
+ // 4️⃣ Remove the wipe element after the animation finishes
+ wipe.addEventListener('animationend', () => wipe.remove());
}
+
function updateScore() {
document.getElementById('score').innerText = score;
document.getElementById('lines').innerText = linesClearedTotal;
}
+ // --------------------------------------------------------------
+ // DIGITAL RAIN (Matrix‑style) – added after the existing script
+ // --------------------------------------------------------------
+
+ // Canvas & context for the rain effect
+ const rainCanvas = document.querySelector('.digital-rain');
+ const rainCtx = rainCanvas.getContext('2d');
+
+ // Resize canvas to fill the viewport
+ function resizeRainCanvas() {
+ rainCanvas.width = window.innerWidth;
+ rainCanvas.height = window.innerHeight;
+ }
+ window.addEventListener('resize', resizeRainCanvas);
+ resizeRainCanvas();
+
+ // Characters used for the rain (feel free to customise)
+ const RAIN_CHARS = 'アァカサタナハマヤラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユルヲグズブポエェケセテネヘメレヱゲゼデベペオォコソトノホモヨロヲゴゾボポ01'.split('');
+
+ // Rain drop definition
+ class RainDrop {
+ constructor(x) {
+ this.x = x; // column (pixel)
+ this.y = Math.random() * -rainCanvas.height; // start above view
+ this.speed = 2 + Math.random() * 3; // fall speed
+ this.char = RAIN_CHARS[Math.floor(Math.random()*RAIN_CHARS.length)];
+ }
+ update(windAngle) {
+ // Apply wind: slight horizontal drift
+ this.x += Math.sin(windAngle) * 0.5;
+ this.y += this.speed + Math.cos(windAngle) * 0.5;
+
+ // Reset when off‑screen
+ if (this.y > rainCanvas.height) {
+ this.y = Math.random() * -100;
+ this.x = Math.random() * rainCanvas.width;
+ this.char = RAIN_CHARS[Math.floor(Math.random()*RAIN_CHARS.length)];
+ }
+ }
+ draw(ctx) {
+ ctx.fillStyle = '#0ff';
+ ctx.font = '16px monospace';
+ ctx.fillText(this.char, this.x, this.y);
+ }
+ }
+
+ // Initialise a pool of drops (one per ~20 px column)
+ let rainDrops = [];
+ function initRain() {
+ rainDrops = [];
+ const cols = Math.floor(rainCanvas.width / 20);
+ for (let i = 0; i < cols; i++) {
+ rainDrops.push(new RainDrop(i * 20));
+ }
+ }
+ initRain();
+
+ // Wind handling
+ let windAngle = 0; // radians
+ function changeWind() {
+ // Random new direction between -30° and +30°
+ windAngle = (Math.random() - 0.5) * (Math.PI / 3);
+ triggerGlitchFlash(); // flash when wind shifts
+ }
+ // Change wind every 8‑12 seconds
+ setInterval(changeWind, 8000 + Math.random() * 4000);
+
+ // Glitch flash helper
+ function triggerGlitchFlash() {
+ document.body.classList.add('glitch-flash');
+ setTimeout(() => document.body.classList.remove('glitch-flash'), 300);
+ }
+
+ // Rain animation loop (runs alongside the game loop)
+ let rainRunning = false;
+ function rainLoop() {
+ if (!rainRunning) return; // stop when game ends
+
+ rainCtx.clearRect(0, 0, rainCanvas.width, rainCanvas.height);
+
+ // Update & draw each drop
+ rainDrops.forEach(drop => {
+ drop.update(windAngle);
+ drop.draw(rainCtx);
+ });
+
+ requestAnimationFrame(rainLoop);
+ }
+
// --- PARTICLE SYSTEM (The Cool Stuff) ---
class Particle {
@@ -786,17 +963,25 @@
playerReset();
startMusic();
update();
+
+ // ---- NEW: start rain ----
+ rainRunning = true;
+ rainLoop();
}
function gameOver() {
document.getElementById('game-over-screen').style.display = 'flex';
cancelAnimationFrame(update);
+ // ---- NEW: stop rain ----
+ rainRunning = false;
}
function resetGame() {
startGame();
}
+
+