Initial commit
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
// seasonal.js — Seasonal background theme (8 variants)
|
||||
// Depends on backgroundEngine.js being loaded first
|
||||
|
||||
(function(engine) {
|
||||
if (!engine) return;
|
||||
var D = engine.Draw, H = engine.helpers;
|
||||
|
||||
engine.registerTheme('seasonal', {
|
||||
|
||||
springMeadow: {
|
||||
meta: { id: 'seasonal_springMeadow', mood: 'cheerful', colors: ['#87CEEB', '#98FB98', '#FFD700', '#FF69B4'], tags: ['spring', 'flowers', 'meadow', 'bright'], description: 'A sunny spring meadow with wildflowers and gentle hills', compatibleMusicMoods: ['happy', 'upbeat', 'peaceful'], recommendedFor: ['puzzle', 'creative', 'pet'] },
|
||||
colors: ['#87CEEB', '#98FB98', '#FFD700', '#FF69B4'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[0], H.lighten(c[0], 0.3)], 90);
|
||||
Draw.hills(ctx, w, h, h * 0.6, 6, c[1], 10);
|
||||
Draw.hills(ctx, w, h, h * 0.7, 8, H.darken(c[1], 0.15), 20);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(42);
|
||||
// Sun
|
||||
Draw.glow(ctx, w * 0.8, h * 0.15, h * 0.12, c[2]);
|
||||
Draw.circle(ctx, w * 0.8, h * 0.15, h * 0.04, c[2]);
|
||||
// Wildflowers across the meadow
|
||||
for (var i = 0; i < 40; i++) {
|
||||
var fx = rng() * w;
|
||||
var fy = h * 0.62 + rng() * h * 0.25;
|
||||
var fs = 3 + rng() * 5;
|
||||
var sway = Math.sin(t * 1.5 + i * 0.7) * 2;
|
||||
// Stem
|
||||
ctx.strokeStyle = H.darken(c[1], 0.2);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath(); ctx.moveTo(fx, fy); ctx.lineTo(fx + sway, fy - fs * 3); ctx.stroke();
|
||||
// Petal
|
||||
var flowerColor = rng() > 0.5 ? c[3] : c[2];
|
||||
Draw.circle(ctx, fx + sway, fy - fs * 3, fs, flowerColor);
|
||||
Draw.circle(ctx, fx + sway, fy - fs * 3, fs * 0.4, '#FFFFFF');
|
||||
}
|
||||
// Butterflies
|
||||
for (var b = 0; b < 5; b++) {
|
||||
var bx = (rng() * w + t * 20 * (b + 1)) % (w + 40) - 20;
|
||||
var by = h * 0.3 + rng() * h * 0.3 + Math.sin(t * 2 + b) * 15;
|
||||
var wingFlap = Math.abs(Math.sin(t * 6 + b * 2)) * 6;
|
||||
ctx.fillStyle = H.rgba(c[3], 0.7);
|
||||
ctx.beginPath(); ctx.ellipse(bx - wingFlap, by, wingFlap, 3, -0.3, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.beginPath(); ctx.ellipse(bx + wingFlap, by, wingFlap, 3, 0.3, 0, Math.PI * 2); ctx.fill();
|
||||
}
|
||||
},
|
||||
particles: { type: 'leaves', count: 10, color: '#FFB7C5' }
|
||||
},
|
||||
|
||||
autumnLeaves: {
|
||||
meta: { id: 'seasonal_autumnLeaves', mood: 'warm', colors: ['#2C1810', '#CC5500', '#DD8833', '#FFD700'], tags: ['autumn', 'fall', 'leaves', 'warm'], description: 'A warm autumn landscape with falling leaves and golden light', compatibleMusicMoods: ['mellow', 'peaceful', 'nostalgic'], recommendedFor: ['puzzle', 'story', 'rpg'] },
|
||||
colors: ['#2C1810', '#CC5500', '#DD8833', '#FFD700'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#D4956B', '#E8A050', '#CC7733'], 90);
|
||||
Draw.hills(ctx, w, h, h * 0.55, 5, '#8B6914', 15);
|
||||
Draw.hills(ctx, w, h, h * 0.65, 7, '#6B4E0A', 25);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(77);
|
||||
// Autumn trees
|
||||
for (var i = 0; i < 12; i++) {
|
||||
var tx = rng() * w;
|
||||
var ty = h * 0.5 + rng() * h * 0.2;
|
||||
var th = 40 + rng() * 50;
|
||||
var tw = 4 + rng() * 4;
|
||||
ctx.fillStyle = c[0];
|
||||
ctx.fillRect(tx - tw / 2, ty - th * 0.4, tw, th * 0.5);
|
||||
var leafCol = [c[1], c[2], c[3]][Math.floor(rng() * 3)];
|
||||
var canopyR = th * 0.35 + Math.sin(t + i) * 2;
|
||||
Draw.circle(ctx, tx, ty - th * 0.55, canopyR, leafCol);
|
||||
Draw.circle(ctx, tx - canopyR * 0.5, ty - th * 0.45, canopyR * 0.7, H.darken(leafCol, 0.15));
|
||||
Draw.circle(ctx, tx + canopyR * 0.4, ty - th * 0.5, canopyR * 0.6, H.lighten(leafCol, 0.1));
|
||||
}
|
||||
// Pumpkins on the ground
|
||||
for (var p = 0; p < 6; p++) {
|
||||
var px = rng() * w;
|
||||
var py = h * 0.72 + rng() * h * 0.15;
|
||||
var ps = 5 + rng() * 7;
|
||||
Draw.circle(ctx, px, py, ps, '#E86800');
|
||||
Draw.circle(ctx, px, py, ps * 0.9, '#FF7700');
|
||||
ctx.fillStyle = '#336600';
|
||||
ctx.fillRect(px - 1, py - ps - 3, 2, 4);
|
||||
}
|
||||
},
|
||||
particles: { type: 'leaves', count: 30, color: '#DD6622' }
|
||||
},
|
||||
|
||||
winterWonderland: {
|
||||
meta: { id: 'seasonal_winterWonderland', mood: 'calm', colors: ['#1A2744', '#4A7CB5', '#C8E0F4', '#FFFFFF'], tags: ['winter', 'snow', 'cold', 'peaceful'], description: 'A serene winter landscape with snow-covered hills and frosty air', compatibleMusicMoods: ['peaceful', 'calm', 'ambient'], recommendedFor: ['puzzle', 'story', 'creative'] },
|
||||
colors: ['#1A2744', '#4A7CB5', '#C8E0F4', '#FFFFFF'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[0], c[1], c[2]], 90);
|
||||
Draw.hills(ctx, w, h, h * 0.6, 5, c[2], 30);
|
||||
Draw.hills(ctx, w, h, h * 0.7, 7, c[3], 40);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(55);
|
||||
// Snow-covered evergreen trees
|
||||
for (var i = 0; i < 15; i++) {
|
||||
var tx = rng() * w;
|
||||
var ty = h * 0.55 + rng() * h * 0.25;
|
||||
var th = 25 + rng() * 45;
|
||||
// Trunk
|
||||
ctx.fillStyle = '#4A3728';
|
||||
ctx.fillRect(tx - 2, ty - 5, 4, 10);
|
||||
// Tree layers
|
||||
for (var layer = 0; layer < 3; layer++) {
|
||||
var lw = th * 0.4 * (1 - layer * 0.25);
|
||||
var ly = ty - 5 - layer * th * 0.25;
|
||||
ctx.fillStyle = '#1B4332';
|
||||
ctx.beginPath(); ctx.moveTo(tx - lw, ly); ctx.lineTo(tx, ly - th * 0.3); ctx.lineTo(tx + lw, ly); ctx.closePath(); ctx.fill();
|
||||
// Snow caps
|
||||
ctx.fillStyle = H.rgba(c[3], 0.8);
|
||||
ctx.beginPath(); ctx.moveTo(tx - lw * 0.7, ly - th * 0.08); ctx.lineTo(tx, ly - th * 0.3); ctx.lineTo(tx + lw * 0.7, ly - th * 0.08); ctx.closePath(); ctx.fill();
|
||||
}
|
||||
}
|
||||
// Distant moon glow
|
||||
var moonY = h * 0.12 + Math.sin(t * 0.1) * 3;
|
||||
Draw.glow(ctx, w * 0.2, moonY, h * 0.08, c[3]);
|
||||
Draw.circle(ctx, w * 0.2, moonY, h * 0.03, c[3]);
|
||||
},
|
||||
particles: { type: 'snow', count: 80, color: '#FFFFFF' }
|
||||
},
|
||||
|
||||
summerBeach: {
|
||||
meta: { id: 'seasonal_summerBeach', mood: 'energetic', colors: ['#0077BE', '#00BFFF', '#F4D03F', '#FF6347'], tags: ['summer', 'beach', 'ocean', 'sunny'], description: 'A vibrant summer beach scene with rolling waves and warm sand', compatibleMusicMoods: ['happy', 'upbeat', 'energetic'], recommendedFor: ['action', 'sports', 'racing'] },
|
||||
colors: ['#0077BE', '#00BFFF', '#F4D03F', '#FF6347'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
|
||||
// Sand
|
||||
Draw.rect(ctx, 0, h * 0.65, w, h * 0.35, c[2]);
|
||||
// Shore wave line
|
||||
ctx.strokeStyle = H.rgba('#FFFFFF', 0.4);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
for (var x = 0; x < w; x += 3) {
|
||||
var wy = h * 0.65 + Math.sin(x * 0.015 + t * 2) * 5 + Math.sin(x * 0.03 + t * 3) * 2;
|
||||
x === 0 ? ctx.moveTo(x, wy) : ctx.lineTo(x, wy);
|
||||
}
|
||||
ctx.stroke();
|
||||
Draw.water(ctx, w, h, h * 0.45, H.rgba(c[0], 0.4), 4, 50);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(88);
|
||||
// Sun
|
||||
Draw.glow(ctx, w * 0.75, h * 0.1, h * 0.15, '#FFD700');
|
||||
Draw.circle(ctx, w * 0.75, h * 0.1, h * 0.05, '#FFE44D');
|
||||
// Palm trees
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var px = w * 0.1 + rng() * w * 0.35;
|
||||
var py = h * 0.65;
|
||||
var ph = 60 + rng() * 40;
|
||||
var lean = (rng() - 0.5) * 0.3;
|
||||
// Curved trunk
|
||||
ctx.strokeStyle = '#8B6914';
|
||||
ctx.lineWidth = 6;
|
||||
ctx.beginPath(); ctx.moveTo(px, py);
|
||||
ctx.quadraticCurveTo(px + lean * ph, py - ph * 0.5, px + lean * ph * 1.5, py - ph);
|
||||
ctx.stroke();
|
||||
// Fronds
|
||||
var topX = px + lean * ph * 1.5, topY = py - ph;
|
||||
for (var f = 0; f < 6; f++) {
|
||||
var angle = (f / 6) * Math.PI * 2 + Math.sin(t * 0.8 + f) * 0.1;
|
||||
var fLen = 25 + rng() * 20;
|
||||
ctx.strokeStyle = '#228B22';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath(); ctx.moveTo(topX, topY);
|
||||
ctx.quadraticCurveTo(topX + Math.cos(angle) * fLen * 0.6, topY + Math.sin(angle) * fLen * 0.3, topX + Math.cos(angle) * fLen, topY + Math.abs(Math.sin(angle)) * fLen * 0.5 + 8);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
// Beach umbrella
|
||||
var ux = w * 0.6, uy = h * 0.58;
|
||||
ctx.fillStyle = '#8B6914';
|
||||
ctx.fillRect(ux - 1.5, uy, 3, h * 0.12);
|
||||
ctx.fillStyle = c[3];
|
||||
ctx.beginPath(); ctx.arc(ux, uy, 25, Math.PI, 0); ctx.fill();
|
||||
ctx.fillStyle = '#FFFFFF';
|
||||
ctx.beginPath(); ctx.arc(ux, uy, 25, Math.PI, Math.PI + Math.PI / 4); ctx.lineTo(ux, uy); ctx.fill();
|
||||
ctx.beginPath(); ctx.arc(ux, uy, 25, Math.PI + Math.PI / 2, Math.PI + Math.PI * 3 / 4); ctx.lineTo(ux, uy); ctx.fill();
|
||||
},
|
||||
particles: { type: 'sparkles', count: 20, color: '#FFE44D' }
|
||||
},
|
||||
|
||||
harvest: {
|
||||
meta: { id: 'seasonal_harvest', mood: 'warm', colors: ['#5C3317', '#D4A017', '#8B4513', '#FFD700'], tags: ['harvest', 'farm', 'autumn', 'golden'], description: 'Golden harvest fields with wheat rows and a warm sunset', compatibleMusicMoods: ['mellow', 'peaceful', 'warm'], recommendedFor: ['puzzle', 'story', 'creative'] },
|
||||
colors: ['#5C3317', '#D4A017', '#8B4513', '#FFD700'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#E8913A', '#F4C54D', c[1]], 90);
|
||||
// Field rows
|
||||
Draw.rect(ctx, 0, h * 0.55, w, h * 0.45, '#B8860B');
|
||||
for (var r = 0; r < 8; r++) {
|
||||
var ry = h * 0.58 + r * h * 0.05;
|
||||
ctx.fillStyle = H.rgba(H.darken(c[1], 0.1 + r * 0.03), 0.6);
|
||||
ctx.fillRect(0, ry, w, 2);
|
||||
}
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(99);
|
||||
// Wheat stalks
|
||||
for (var i = 0; i < 60; i++) {
|
||||
var wx = rng() * w;
|
||||
var wy = h * 0.56 + rng() * h * 0.35;
|
||||
var wh = 15 + rng() * 25;
|
||||
var sway = Math.sin(t * 1.2 + i * 0.5) * 3;
|
||||
ctx.strokeStyle = H.rgba(c[1], 0.7);
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.beginPath(); ctx.moveTo(wx, wy); ctx.lineTo(wx + sway, wy - wh); ctx.stroke();
|
||||
// Wheat head
|
||||
ctx.fillStyle = c[3];
|
||||
ctx.beginPath(); ctx.ellipse(wx + sway, wy - wh - 3, 2, 5, 0, 0, Math.PI * 2); ctx.fill();
|
||||
}
|
||||
// Sunset glow
|
||||
Draw.glow(ctx, w * 0.5, h * 0.12, h * 0.18, '#FF8C00');
|
||||
Draw.circle(ctx, w * 0.5, h * 0.12, h * 0.06, '#FFD700');
|
||||
// Barn silhouette
|
||||
var bx = w * 0.78, by = h * 0.48, bw = 50, bh = 35;
|
||||
ctx.fillStyle = c[2];
|
||||
ctx.fillRect(bx, by, bw, bh);
|
||||
ctx.beginPath(); ctx.moveTo(bx - 5, by); ctx.lineTo(bx + bw / 2, by - 25); ctx.lineTo(bx + bw + 5, by); ctx.closePath();
|
||||
ctx.fillStyle = H.darken(c[2], 0.2);
|
||||
ctx.fill();
|
||||
// Silo
|
||||
ctx.fillStyle = c[2];
|
||||
ctx.fillRect(bx + bw + 8, by - 10, 12, bh + 10);
|
||||
ctx.beginPath(); ctx.arc(bx + bw + 14, by - 10, 6, 0, Math.PI * 2); ctx.fill();
|
||||
},
|
||||
particles: { type: 'dust', count: 20, color: '#DDCC88' }
|
||||
},
|
||||
|
||||
blossom: {
|
||||
meta: { id: 'seasonal_blossom', mood: 'peaceful', colors: ['#FFB7C5', '#FF69B4', '#FFF0F5', '#98FB98'], tags: ['spring', 'cherry', 'blossom', 'pink'], description: 'Gentle cherry blossom petals drifting under pink-tinted skies', compatibleMusicMoods: ['peaceful', 'calm', 'romantic'], recommendedFor: ['puzzle', 'story', 'creative', 'music'] },
|
||||
colors: ['#FFB7C5', '#FF69B4', '#FFF0F5', '#98FB98'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[2], c[0], H.lighten(c[3], 0.3)], 90);
|
||||
Draw.hills(ctx, w, h, h * 0.7, 6, c[3], 12);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(33);
|
||||
// Cherry blossom trees
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var tx = w * 0.1 + rng() * w * 0.8;
|
||||
var ty = h * 0.65 + rng() * h * 0.1;
|
||||
var th = 50 + rng() * 40;
|
||||
// Trunk and branches
|
||||
ctx.strokeStyle = '#5C3A1E';
|
||||
ctx.lineWidth = 4 + rng() * 3;
|
||||
ctx.beginPath(); ctx.moveTo(tx, ty); ctx.quadraticCurveTo(tx + rng() * 10 - 5, ty - th * 0.5, tx, ty - th); ctx.stroke();
|
||||
// Branch clusters
|
||||
for (var b = 0; b < 4; b++) {
|
||||
var bAngle = (rng() - 0.5) * Math.PI * 0.8;
|
||||
var bLen = 15 + rng() * 25;
|
||||
var bStartY = ty - th * (0.5 + rng() * 0.4);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath(); ctx.moveTo(tx, bStartY);
|
||||
ctx.lineTo(tx + Math.cos(bAngle) * bLen, bStartY + Math.sin(bAngle) * bLen - 10);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Blossom clouds
|
||||
for (var bc = 0; bc < 6; bc++) {
|
||||
var bx = tx + (rng() - 0.5) * th * 0.8;
|
||||
var by = ty - th * (0.4 + rng() * 0.5);
|
||||
var br = 8 + rng() * 15;
|
||||
var pulseR = br + Math.sin(t * 0.8 + i + bc) * 1.5;
|
||||
Draw.circle(ctx, bx, by, pulseR, H.rgba(c[0], 0.5 + rng() * 0.3));
|
||||
Draw.circle(ctx, bx + br * 0.3, by - br * 0.2, pulseR * 0.7, H.rgba(c[1], 0.3));
|
||||
}
|
||||
}
|
||||
// Soft light
|
||||
Draw.glow(ctx, w * 0.5, h * 0.08, h * 0.12, '#FFF5EE');
|
||||
},
|
||||
particles: { type: 'leaves', count: 25, color: '#FFB7C5' }
|
||||
},
|
||||
|
||||
snowfall: {
|
||||
meta: { id: 'seasonal_snowfall', mood: 'calm', colors: ['#0D1B2A', '#1B2838', '#415A77', '#E0E1DD'], tags: ['winter', 'night', 'snow', 'dark'], description: 'Heavy snowfall over a dark winter night with distant lights', compatibleMusicMoods: ['calm', 'ambient', 'mysterious'], recommendedFor: ['puzzle', 'story', 'rpg'] },
|
||||
colors: ['#0D1B2A', '#1B2838', '#415A77', '#E0E1DD'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
|
||||
Draw.mountains(ctx, w, h, h * 0.5, 6, c[2], 60);
|
||||
Draw.hills(ctx, w, h, h * 0.7, 5, H.lighten(c[2], 0.2), 70);
|
||||
// Snow ground
|
||||
Draw.rect(ctx, 0, h * 0.78, w, h * 0.22, H.rgba(c[3], 0.3));
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(44);
|
||||
// Distant village lights
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var lx = rng() * w;
|
||||
var ly = h * 0.55 + rng() * h * 0.15;
|
||||
var twinkle = 0.3 + Math.sin(t * 2 + i * 1.5) * 0.2;
|
||||
Draw.glow(ctx, lx, ly, 8, H.rgba('#FFD700', twinkle));
|
||||
Draw.circle(ctx, lx, ly, 1.5, H.rgba('#FFE088', twinkle + 0.3));
|
||||
}
|
||||
// Bare tree silhouettes
|
||||
for (var tr = 0; tr < 6; tr++) {
|
||||
var tx = rng() * w;
|
||||
var ty = h * 0.75 + rng() * h * 0.05;
|
||||
var th = 30 + rng() * 40;
|
||||
ctx.strokeStyle = H.rgba(c[0], 0.6);
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath(); ctx.moveTo(tx, ty); ctx.lineTo(tx, ty - th); ctx.stroke();
|
||||
// Branches
|
||||
for (var br = 0; br < 4; br++) {
|
||||
var brY = ty - th * (0.3 + br * 0.18);
|
||||
var brDir = br % 2 === 0 ? 1 : -1;
|
||||
var brLen = 8 + rng() * 15;
|
||||
ctx.beginPath(); ctx.moveTo(tx, brY);
|
||||
ctx.lineTo(tx + brDir * brLen, brY - brLen * 0.6);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
// Snow on ground — gentle undulation
|
||||
ctx.fillStyle = H.rgba(c[3], 0.15);
|
||||
ctx.beginPath(); ctx.moveTo(0, h);
|
||||
for (var x = 0; x <= w; x += 20) {
|
||||
ctx.lineTo(x, h * 0.78 + Math.sin(x * 0.03 + t * 0.3) * 4);
|
||||
}
|
||||
ctx.lineTo(w, h); ctx.closePath(); ctx.fill();
|
||||
},
|
||||
particles: { type: 'snow', count: 120, color: '#E0E1DD' }
|
||||
},
|
||||
|
||||
tropical: {
|
||||
meta: { id: 'seasonal_tropical', mood: 'energetic', colors: ['#00CED1', '#FF6347', '#228B22', '#FFD700'], tags: ['summer', 'tropical', 'jungle', 'vibrant'], description: 'A lush tropical scene with dense foliage and vivid colors', compatibleMusicMoods: ['energetic', 'upbeat', 'happy'], recommendedFor: ['action', 'racing', 'sports', 'pet'] },
|
||||
colors: ['#00CED1', '#FF6347', '#228B22', '#FFD700'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [H.lighten(c[0], 0.2), c[0]], 90);
|
||||
Draw.hills(ctx, w, h, h * 0.5, 4, c[2], 35);
|
||||
Draw.hills(ctx, w, h, h * 0.6, 6, H.darken(c[2], 0.2), 45);
|
||||
// Jungle floor
|
||||
Draw.rect(ctx, 0, h * 0.75, w, h * 0.25, H.darken(c[2], 0.35));
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(66);
|
||||
// Tropical flowers
|
||||
for (var i = 0; i < 20; i++) {
|
||||
var fx = rng() * w;
|
||||
var fy = h * 0.55 + rng() * h * 0.3;
|
||||
var fs = 4 + rng() * 6;
|
||||
var bloom = fs + Math.sin(t + i * 0.8) * 1;
|
||||
var flColor = rng() > 0.5 ? c[1] : c[3];
|
||||
// Petals
|
||||
ctx.save(); ctx.translate(fx, fy);
|
||||
for (var p = 0; p < 5; p++) {
|
||||
ctx.rotate(Math.PI * 2 / 5);
|
||||
ctx.fillStyle = H.rgba(flColor, 0.7);
|
||||
ctx.beginPath(); ctx.ellipse(0, -bloom, bloom * 0.4, bloom, 0, 0, Math.PI * 2); ctx.fill();
|
||||
}
|
||||
ctx.restore();
|
||||
Draw.circle(ctx, fx, fy, bloom * 0.3, '#FFFFFF');
|
||||
}
|
||||
// Large palm fronds at edges
|
||||
for (var f = 0; f < 3; f++) {
|
||||
var side = f % 2 === 0 ? 0 : w;
|
||||
var dir = f % 2 === 0 ? 1 : -1;
|
||||
var fy2 = h * 0.05 + f * h * 0.15;
|
||||
var sway = Math.sin(t * 0.5 + f) * 8;
|
||||
ctx.strokeStyle = c[2];
|
||||
ctx.lineWidth = 4;
|
||||
for (var fr = 0; fr < 4; fr++) {
|
||||
var angle = (0.2 + fr * 0.3) * dir;
|
||||
ctx.beginPath(); ctx.moveTo(side, fy2 + fr * 20);
|
||||
ctx.quadraticCurveTo(side + dir * (60 + sway), fy2 + fr * 20 + 30, side + dir * (100 + sway), fy2 + fr * 20 + 60);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
// Parrots
|
||||
for (var b = 0; b < 3; b++) {
|
||||
var bx = (rng() * w + t * 15 * (b + 1)) % (w + 30) - 15;
|
||||
var by = h * 0.15 + rng() * h * 0.2 + Math.sin(t * 1.5 + b * 2) * 10;
|
||||
var wingF = Math.abs(Math.sin(t * 5 + b * 3)) * 5;
|
||||
ctx.fillStyle = [c[1], c[3], '#00AA44'][b % 3];
|
||||
ctx.beginPath(); ctx.ellipse(bx, by, 4, 2.5, 0, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.fillStyle = H.rgba('#000000', 0.4);
|
||||
ctx.beginPath(); ctx.ellipse(bx - wingF * 0.8, by - 1, wingF, 2, -0.4, 0, Math.PI * 2); ctx.fill();
|
||||
ctx.beginPath(); ctx.ellipse(bx + wingF * 0.8, by - 1, wingF, 2, 0.4, 0, Math.PI * 2); ctx.fill();
|
||||
}
|
||||
},
|
||||
particles: { type: 'fireflies', count: 15, color: '#CCFF44' }
|
||||
}
|
||||
|
||||
});
|
||||
})(window.BackgroundEngine);
|
||||
Reference in New Issue
Block a user