Wednesday, December 31, 2025

A Happy New Year 2026



Dear readers,


Thanks for reading my Blog so frequently in 2025. As a present, I‘ll provide you a HTML file created by Gemini 2.5 Flash.

Please, save and open the following HTML-page. It is safe to do so!



<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Happy New Year! - Dynamic Scenery</title>

    <style>

        body {

            margin: 0;

            overflow: hidden; /* Hide scrollbars */

            background: linear-gradient(to bottom, #0a0a2a 0%, #2c0a4e 100%); /* Dark night sky */

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            display: flex;

            justify-content: center;

            align-items: center;

            min-height: 100vh;

            position: relative;

            color: #fff; /* Default text color */

        }


        /* Canvas for fireworks */

        #fireworksCanvas {

            position: absolute;

            top: 0;

            left: 0;

            width: 100%;

            height: 100%;

            z-index: 1; /* Above city, below text */

        }


        /* "Happy New Year!" Text */

        #new-year-text {

            position: absolute;

            top: 20%; /* Adjust vertical position */

            left: 50%;

            transform: translate(-50%, -50%);

            font-size: 5em; /* Large font size */

            font-weight: bold;

            text-shadow: 0 0 15px rgba(255, 255, 255, 0.8), 0 0 30px rgba(255, 255, 255, 0.6), 0 0 45px rgba(255, 255, 255, 0.4);

            letter-spacing: 5px;

            z-index: 2; /* On top of everything */

            animation: pulseText 3s infinite alternate; /* Subtle breathing effect */

            white-space: nowrap; /* Prevent text wrapping */

        }


        #new-year-text span {

            display: block; /* Ensures text shadow applies properly */

            background: linear-gradient(45deg, #ffd700, #ff8c00, #ff4500); /* Gold/Orange gradient */

            -webkit-background-clip: text;

            -webkit-text-fill-color: transparent;

            background-clip: text; /* Standard property */

            color: transparent; /* Fallback for browsers without -webkit-text-fill-color */

        }


        @keyframes pulseText {

            0% {

                transform: translate(-50%, -50%) scale(1);

                opacity: 0.9;

            }

            100% {

                transform: translate(-50%, -50%) scale(1.02);

                opacity: 1;

            }

        }


        /* City Silhouette at the bottom */

        #city-silhouette {

            position: absolute;

            bottom: 0;

            left: 0;

            width: 100%;

            height: 150px; /* Height of the silhouette */

            background: #000; /* Solid black silhouette */

            z-index: 0; /* Behind fireworks */

            /* Using a simple SVG mask for a jagged city skyline effect */

            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path fill="black" d="M0 100 L0 50 L10 50 L10 70 L20 70 L20 40 L30 40 L30 80 L40 80 L40 60 L50 60 L50 90 L60 90 L60 70 L70 70 L70 50 L80 50 L80 80 L90 80 L90 60 L100 60 L100 100 Z"/></svg>');

            mask-size: 100% 100%;

            mask-repeat: no-repeat;

            -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path fill="black" d="M0 100 L0 50 L10 50 L10 70 L20 70 L20 40 L30 40 L30 80 L40 80 L40 60 L50 60 L50 90 L60 90 L60 70 L70 70 L70 50 L80 50 L80 80 L90 80 L90 60 L100 60 L100 100 Z"/></svg>');

            -webkit-mask-size: 100% 100%;

            -webkit-mask-repeat: no-repeat;

        }


        /* Twinkling Stars (added via JavaScript) */

        .star {

            position: absolute;

            background-color: white;

            border-radius: 50%;

            animation: twinkle 2s infinite alternate;

            opacity: 0; /* Start invisible */

            z-index: 0; /* Behind fireworks */

        }


        @keyframes twinkle {

            0% { opacity: 0; transform: scale(0.5); }

            50% { opacity: 1; transform: scale(1); }

            100% { opacity: 0; transform: scale(0.5); }

        }

    </style>

</head>

<body>

    <div id="new-year-text">

        <span>Happy New Year!</span>

    </div>

    <canvas id="fireworksCanvas"></canvas>

    <div id="city-silhouette"></div>


    <script>

        const canvas = document.getElementById('fireworksCanvas');

        const ctx = canvas.getContext('2d');


        let fireworks = [];

        let particles = [];


        // Set canvas dimensions to full window size

        function setCanvasSize() {

            canvas.width = window.innerWidth;

            canvas.height = window.innerHeight;

        }

        setCanvasSize();

        window.addEventListener('resize', setCanvasSize);


        // Utility function to get a random vibrant color

        function getRandomColor() {

            const hue = Math.floor(Math.random() * 360);

            return `hsl(${hue}, 100%, 70%)`; // High saturation, medium lightness for vibrancy

        }


        // Particle class for firework trails and explosion fragments

        class Particle {

            constructor(x, y, vx, vy, color, alphaDecay, size) {

                this.x = x;

                this.y = y;

                this.vx = vx;

                this.vy = vy;

                this.color = color;

                this.alpha = 1;

                this.alphaDecay = alphaDecay; // How fast the particle fades

                this.size = size;

                this.gravity = 0.05; // Affects how particles fall

                this.friction = 0.99; // Slows down particles over time

            }


            update() {

                this.vx *= this.friction;

                this.vy *= this.friction;

                this.vy += this.gravity; // Apply gravity

                this.x += this.vx;

                this.y += this.vy;

                this.alpha -= this.alphaDecay; // Fade out

            }


            draw() {

                ctx.save();

                ctx.globalAlpha = Math.max(0, this.alpha); // Ensure alpha doesn't go below 0

                ctx.beginPath();

                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);

                ctx.fillStyle = this.color;

                ctx.shadowBlur = this.size * 2; // Create a glow effect

                ctx.shadowColor = this.color;

                ctx.fill();

                ctx.restore();

            }

        }


        // Firework class for the rocket and its explosion logic

        class Firework {

            constructor(startX, startY, targetX, targetY) {

                this.x = startX;

                this.y = startY;

                this.targetX = targetX;

                this.targetY = targetY;


                // Calculate velocity to reach target

                const angle = Math.atan2(targetY - startY, targetX - startX);

                this.speed = 5; // Initial rocket speed

                this.vx = Math.cos(angle) * this.speed;

                this.vy = Math.sin(angle) * this.speed;


                this.color = getRandomColor();

                this.trail = []; // Particles forming the rocket's trail

                this.exploded = false;

            }


            update() {

                if (!this.exploded) {

                    // Check if firework has reached its target

                    const distanceToTarget = Math.sqrt((this.x - this.targetX)**2 + (this.y - this.targetY)**2);

                    if (distanceToTarget <= this.speed) {

                        this.exploded = true;

                        this.explode(); // Trigger explosion

                    } else {

                        this.x += this.vx;

                        this.y += this.vy;

                        // Add particles to the rocket's trail

                        this.trail.push(new Particle(this.x, this.y, 0, 0, this.color, 0.02, 1.5));

                        if (this.trail.length > 20) { // Limit trail length for performance

                            this.trail.shift();

                        }

                    }

                }

                // Update and remove faded trail particles

                for (let i = this.trail.length - 1; i >= 0; i--) {

                    this.trail[i].update();

                    if (this.trail[i].alpha <= 0.05) {

                        this.trail.splice(i, 1);

                    }

                }

            }


            draw() {

                if (!this.exploded) {

                    // Draw the rocket itself

                    ctx.save();

                    ctx.beginPath();

                    ctx.arc(this.x, this.y, 3, 0, Math.PI * 2);

                    ctx.fillStyle = this.color;

                    ctx.shadowBlur = 10;

                    ctx.shadowColor = this.color;

                    ctx.fill();

                    ctx.restore();

                }

                // Draw the rocket's trail

                this.trail.forEach(p => p.draw());

            }


            explode() {

                const numParticles = 80 + Math.random() * 50; // Random number of explosion particles

                for (let i = 0; i < numParticles; i++) {

                    const angle = Math.random() * Math.PI * 2; // Random direction

                    const speed = Math.random() * 8 + 2; // Random speed

                    const vx = Math.cos(angle) * speed;

                    const vy = Math.sin(angle) * speed;

                    const size = Math.random() * 3 + 1; // Random size

                    particles.push(new Particle(this.x, this.y, vx, vy, this.color, 0.02, size));

                }

            }

        }


        // Main animation loop

        function animate() {

            requestAnimationFrame(animate); // Call animate again on next frame


            // Clear canvas with a fading effect to create trails

            ctx.globalCompositeOperation = 'destination-out';

            ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; // Fades out previous frames

            ctx.fillRect(0, 0, canvas.width, canvas.height);

            ctx.globalCompositeOperation = 'lighter'; // Blend mode for glowing particles


            // Update and draw fireworks

            for (let i = fireworks.length - 1; i >= 0; i--) {

                fireworks[i].update();

                fireworks[i].draw();


                // Remove firework if it exploded and its trail has faded

                if (fireworks[i].exploded && fireworks[i].trail.length === 0) {

                    fireworks.splice(i, 1);

                }

            }


            // Update and draw explosion particles

            for (let i = particles.length - 1; i >= 0; i--) {

                particles[i].update();

                particles[i].draw();


                // Remove particle if it has faded out

                if (particles[i].alpha <= 0.05) {

                    particles.splice(i, 1);

                }

            }

        }


        // Function to launch a new firework from the bottom center

        function launchFirework() {

            const startX = canvas.width / 2;

            const startY = canvas.height; // Start from bottom

            const targetX = Math.random() * canvas.width * 0.8 + canvas.width * 0.1; // Random target X (within 10%-90% of width)

            const targetY = Math.random() * canvas.height * 0.5 + canvas.height * 0.1; // Random target Y (within 10%-60% of height)

            fireworks.push(new Firework(startX, startY, targetX, targetY));

        }


        // Launch fireworks periodically

        setInterval(launchFirework, 1000); // Launch a new firework every 1 second


        // Initial launch to start the show

        launchFirework();


        // Start the animation loop

        animate();


        // Optional: Add twinkling stars to the background using JS

        function createStars(numStars) {

            const starsContainer = document.body;

            for (let i = 0; i < numStars; i++) {

                const star = document.createElement('div');

                star.classList.add('star');

                star.style.width = star.style.height = `${Math.random() * 2 + 1}px`; // Random size 1-3px

                star.style.top = `${Math.random() * 100}%`;

                star.style.left = `${Math.random() * 100}%`;

                star.style.animationDelay = `${Math.random() * 2}s`; // Stagger animation start

                star.style.animationDuration = `${Math.random() * 1.5 + 1.5}s`; // Random animation duration

                starsContainer.appendChild(star);

            }

        }

        createStars(100); // Create 100 twinkling stars

    </script>

</body>

</html>


No comments: