🎮ArcadeLab

AUTUMN BREEZE: UPGRADED

by ThunderPhoenix57
429 lines13.5 KB
▶ Play
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>AUTUMN BREEZE: UPGRADED</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
            -webkit-user-select: none;
            touch-action: none;
        }

        body {
            background: radial-gradient(circle at 50% 30%, #f4f1eb 0%, #e3dbcc 100%);
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            width: 100vw;
            font-family: 'Georgia', serif;
            color: #4a3f35;
        }

        canvas {
            display: block;
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 1;
        }

        #ui-layer {
            position: absolute;
            bottom: 40px;
            z-index: 10;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 20px;
            pointer-events: none;
        }

        #hint {
            color: rgba(74, 63, 53, 0.5);
            font-size: 0.85rem;
            letter-spacing: 3px;
            text-transform: uppercase;
            transition: opacity 1s ease;
            text-shadow: 0 1px 2px rgba(255,255,255,0.5);
        }

        .btn-group {
            display: flex;
            gap: 12px;
            pointer-events: auto;
        }

        button {
            background: rgba(244, 241, 235, 0.7);
            backdrop-filter: blur(5px);
            -webkit-backdrop-filter: blur(5px);
            border: 1px solid rgba(138, 115, 92, 0.3);
            color: #5c4e41;
            padding: 12px 28px;
            font-size: 0.85rem;
            font-weight: bold;
            letter-spacing: 1.5px;
            border-radius: 30px;
            cursor: pointer;
            transition: all 0.2s ease;
            box-shadow: 0 4px 12px rgba(0,0,0,0.06);
        }

        button:hover {
            background: rgba(255, 255, 255, 0.9);
            transform: translateY(-2px);
            box-shadow: 0 6px 15px rgba(0,0,0,0.1);
        }

        button:active {
            transform: translateY(1px);
            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
        }
    </style>
</head>
<body>

    <div id="ui-layer">
        <div id="hint">GENTLY SWIPE TO RUSTLE</div>
        <div class="btn-group">
            <button onclick="spawnLeaves(12)">DROP LEAVES</button>
            <button onclick="clearLeaves()">SWEEP</button>
        </div>
    </div>
    <canvas id="canvas"></canvas>

<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const hint = document.getElementById('hint');

    let width, height;
    let leaves = [];
    let winds = [];
    let dust = [];
    
    // Rich, natural autumn palette
    const colors = [
        '#8B2312', // Deep crimson
        '#A93F16', // Burnt orange
        '#C97A1E', // Golden yellow
        '#D6A127', // Bright gold
        '#716335', // Faded olive
        '#5A422B'  // Crisp brown
    ];

    let pointer = { x: -1000, y: -1000, px: -1000, py: -1000, isDown: false };

    function resize() {
        width = canvas.width = window.innerWidth;
        height = canvas.height = window.innerHeight;
        initDust();
    }
    window.addEventListener('resize', resize);

    class DustMote {
        constructor() {
            this.x = Math.random() * width;
            this.y = Math.random() * height;
            this.vx = (Math.random() - 0.5) * 0.3;
            this.vy = (Math.random() - 0.5) * 0.3 - 0.1;
            this.size = Math.random() * 2 + 0.5;
            this.alpha = Math.random() * 0.3 + 0.1;
        }
        update() {
            this.x += this.vx;
            this.y += this.vy;
            if (this.y < -10) this.y = height + 10;
            if (this.x < -10) this.x = width + 10;
            if (this.x > width + 10) this.x = -10;
        }
        draw() {
            ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    class Leaf {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.vx = (Math.random() - 0.5) * 1.5;
            this.vy = Math.random() * 1.5 + 0.5;
            
            // Increased variation in size
            this.size = Math.random() * 22 + 18; 
            this.color = colors[Math.floor(Math.random() * colors.length)];
            
            // 4 Distinct types for high variation
            this.type = Math.floor(Math.random() * 4); 
            
            this.rotation = Math.random() * Math.PI * 2;
            this.spinSpeed = (Math.random() - 0.5) * 0.08;
            this.wobblePhase = Math.random() * Math.PI * 2;
            this.wobbleSpeed = Math.random() * 0.04 + 0.015;
            
            this.mass = this.size * 0.15;
            this.settled = false;
            this.groundY = height - 15 + (Math.random() * 10 - 5); // Slight depth to the floor
        }

        update() {
            if (!this.settled) {
                // Ambient wobble
                this.wobblePhase += this.wobbleSpeed;
                this.vx += Math.sin(this.wobblePhase) * 0.03;
            }

            // Apply wind forces (Softened drastically)
            for (let w of winds) {
                let dx = this.x - w.x;
                let dy = this.y - w.y;
                let dist = Math.hypot(dx, dy);
                if (dist < w.radius) {
                    let force = Math.pow(1 - dist / w.radius, 2) * w.strength; // Smoother falloff
                    this.vx += (w.vx * force) / this.mass;
                    this.vy += (w.vy * force) / this.mass;
                    this.spinSpeed += (Math.random() - 0.5) * force * 0.05;
                    
                    if (this.settled && force > 0.05) {
                        this.settled = false;
                        this.vy -= 1.5; // Gentle lift off the ground
                    }
                }
            }

            // Physics
            this.vx *= 0.94;
            this.vy *= 0.94;
            if (!this.settled) {
                this.vy += 0.06; // Very gentle gravity
                this.rotation += this.spinSpeed;
            }

            this.x += this.vx;
            this.y += this.vy;

            // Floor collision
            if (this.y > this.groundY) {
                this.y = this.groundY;
                this.vy = 0;
                this.vx *= 0.7;
                this.spinSpeed *= 0.7;
                if (Math.abs(this.vx) < 0.05) {
                    this.settled = true;
                }
            }
            
            // Screen wrap horizontally
            if (this.x < -this.size * 2) this.x = width + this.size * 2;
            if (this.x > width + this.size * 2) this.x = -this.size * 2;
        }

        draw() {
            ctx.save();
            ctx.translate(this.x, this.y);
            ctx.rotate(this.rotation);
            
            // Dynamic Shadow (higher = blurrier/further, settled = tight)
            let shadowDist = this.settled ? 2 : Math.min(15, (this.groundY - this.y) * 0.2);
            let shadowBlur = this.settled ? 3 : Math.min(10, (this.groundY - this.y) * 0.15);
            ctx.shadowColor = 'rgba(0, 0, 0, 0.25)';
            ctx.shadowBlur = shadowBlur;
            ctx.shadowOffsetX = shadowDist * 0.5;
            ctx.shadowOffsetY = shadowDist;
            
            ctx.fillStyle = this.color;
            ctx.beginPath();

            // DISTINCT SHAPES
            if (this.type === 0) {
                // Birch (teardrop/spade)
                ctx.moveTo(0, -this.size);
                ctx.bezierCurveTo(this.size * 0.8, -this.size * 0.2, this.size * 0.6, this.size, 0, this.size);
                ctx.bezierCurveTo(-this.size * 0.6, this.size, -this.size * 0.8, -this.size * 0.2, 0, -this.size);
            } else if (this.type === 1) {
                // Willow (long and thin)
                ctx.moveTo(0, -this.size * 1.2);
                ctx.quadraticCurveTo(this.size * 0.4, 0, 0, this.size * 1.2);
                ctx.quadraticCurveTo(-this.size * 0.4, 0, 0, -this.size * 1.2);
            } else if (this.type === 2) {
                // Oak (lobed)
                let s = this.size * 0.8;
                ctx.moveTo(0, -s*1.2);
                ctx.bezierCurveTo(s*0.5, -s*1.2, s*0.8, -s*0.6, s*0.4, -s*0.3);
                ctx.bezierCurveTo(s*1.1, -s*0.1, s*1.1, s*0.5, s*0.5, s*0.6);
                ctx.bezierCurveTo(s*0.6, s*1.1, s*0.1, s*1.2, 0, s*1.2);
                ctx.bezierCurveTo(-s*0.1, s*1.2, -s*0.6, s*1.1, -s*0.5, s*0.6);
                ctx.bezierCurveTo(-s*1.1, s*0.5, -s*1.1, -s*0.1, -s*0.4, -s*0.3);
                ctx.bezierCurveTo(-s*0.8, -s*0.6, -s*0.5, -s*1.2, 0, -s*1.2);
            } else {
                // Maple (jagged)
                let s = this.size;
                ctx.moveTo(0, -s);
                ctx.lineTo(s*0.3, -s*0.3);
                ctx.lineTo(s*0.9, -s*0.4);
                ctx.lineTo(s*0.5, 0);
                ctx.lineTo(s*0.8, s*0.6);
                ctx.lineTo(s*0.2, s*0.4);
                ctx.lineTo(0, s);
                ctx.lineTo(-s*0.2, s*0.4);
                ctx.lineTo(-s*0.8, s*0.6);
                ctx.lineTo(-s*0.5, 0);
                ctx.lineTo(-s*0.9, -s*0.4);
                ctx.lineTo(-s*0.3, -s*0.3);
            }

            ctx.fill();
            
            // Veins (Subtle)
            ctx.shadowColor = 'transparent'; // No shadow for the inside lines
            ctx.strokeStyle = 'rgba(0,0,0,0.12)';
            ctx.lineWidth = 1.5;
            ctx.beginPath();
            ctx.moveTo(0, -this.size * 0.85);
            ctx.lineTo(0, this.size * 0.85);
            ctx.stroke();

            ctx.restore();
        }
    }

    class WindGust {
        constructor(x, y, vx, vy) {
            this.x = x;
            this.y = y;
            this.vx = vx;
            this.vy = vy;
            // Radius and strength greatly reduced per request
            this.radius = 70; 
            this.strength = Math.min(Math.hypot(vx, vy) * 0.1, 2.5);
            this.life = 1.0;
        }
        update() {
            this.x += this.vx;
            this.y += this.vy;
            this.vx *= 0.85;
            this.vy *= 0.85;
            this.life -= 0.08;
        }
    }

    function spawnLeaves(count = 1) {
        for (let i = 0; i < count; i++) {
            leaves.push(new Leaf(Math.random() * width, -50 - Math.random() * 150));
        }
    }

    function clearLeaves() {
        leaves = [];
    }
    
    function initDust() {
        dust = [];
        for(let i=0; i<40; i++) dust.push(new DustMote());
    }

    function animate() {
        ctx.clearRect(0, 0, width, height);

        // Update and draw dust motes
        dust.forEach(d => {
            d.update();
            d.draw();
        });

        // Update winds
        for (let i = winds.length - 1; i >= 0; i--) {
            winds[i].update();
            if (winds[i].life <= 0) winds.splice(i, 1);
        }

        // Draw settled leaves first (background) then moving leaves (foreground)
        leaves.forEach(leaf => leaf.update());
        
        leaves.filter(l => l.settled).forEach(leaf => leaf.draw());
        leaves.filter(l => !l.settled).forEach(leaf => leaf.draw());

        requestAnimationFrame(animate);
    }

    // Input Handling for Gentle Wind
    function setPointer(e) {
        if (e.touches) {
            pointer.x = e.touches[0].clientX;
            pointer.y = e.touches[0].clientY;
        } else {
            pointer.x = e.clientX;
            pointer.y = e.clientY;
        }
    }

    window.addEventListener('mousedown', (e) => { 
        if(e.target.tagName === 'BUTTON') return;
        pointer.isDown = true; 
        setPointer(e); 
        pointer.px = pointer.x;
        pointer.py = pointer.y;
        hint.style.opacity = '0'; 
    });
    
    window.addEventListener('mousemove', (e) => { 
        if (!pointer.isDown) return;
        setPointer(e);
        let dx = pointer.x - pointer.px;
        let dy = pointer.y - pointer.py;
        
        if (Math.hypot(dx, dy) > 2) {
            winds.push(new WindGust(pointer.x, pointer.y, dx, dy));
            pointer.px = pointer.x;
            pointer.py = pointer.y;
        }
    });
    
    window.addEventListener('mouseup', () => { pointer.isDown = false; });

    window.addEventListener('touchstart', (e) => { 
        if(e.target.tagName === 'BUTTON') return;
        pointer.isDown = true; 
        setPointer(e); 
        pointer.px = pointer.x;
        pointer.py = pointer.y;
        hint.style.opacity = '0'; 
    }, {passive: false});
    
    window.addEventListener('touchmove', (e) => { 
        if(e.target.tagName !== 'BUTTON') e.preventDefault();
        if (!pointer.isDown) return;
        setPointer(e);
        let dx = pointer.x - pointer.px;
        let dy = pointer.y - pointer.py;
        
        if (Math.hypot(dx, dy) > 2) {
            winds.push(new WindGust(pointer.x, pointer.y, dx, dy));
            pointer.px = pointer.x;
            pointer.py = pointer.y;
        }
    }, {passive: false});
    
    window.addEventListener('touchend', () => { pointer.isDown = false; });

    // Initialize
    resize();
    setTimeout(() => spawnLeaves(25), 300);
    animate();
</script>
</body>
</html>

Game Source: AUTUMN BREEZE: UPGRADED

Creator: ThunderPhoenix57

Libraries: none

Complexity: complex (429 lines, 13.5 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: autumn-breeze-upgraded-thunderphoenix57" to link back to the original. Then publish at arcadelab.ai/publish.