AUTUMN BREEZE: UPGRADED
by ThunderPhoenix57429 lines13.5 KB
<!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.