Initial commit
This commit is contained in:
@@ -0,0 +1,360 @@
|
||||
// nature.js — Nature theme for procedural background system
|
||||
// 8 variants: forest, jungle, desert, mountains, ocean, underwater, waterfall, meadow
|
||||
|
||||
(function(engine) {
|
||||
if (!engine) return;
|
||||
var D = engine.Draw, H = engine.helpers;
|
||||
|
||||
engine.registerTheme('nature', {
|
||||
|
||||
forest: {
|
||||
meta: { id: 'nature_forest', mood: 'peaceful', colors: ['#1A3320', '#2D5A27', '#4A7A3F', '#8FB86A'], tags: ['trees', 'green', 'calm'], description: 'A dense forest with layered canopy and dappled light', compatibleMusicMoods: ['calm', 'ambient', 'dreamy'], recommendedFor: ['story', 'rpg', 'puzzle'] },
|
||||
colors: ['#1A3320', '#2D5A27', '#4A7A3F', '#8FB86A'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#5588AA', '#88BBCC', c[1]], 90);
|
||||
Draw.clouds(ctx, w, h, h * 0.08, 5, '#FFFFFF', 110);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Background tree layer
|
||||
Draw.hills(ctx, w, h, h * 0.4, 8, H.darken(c[0], 0.3), 111);
|
||||
Draw.trees(ctx, w, h, h * 0.5, 25, '#3D2B1F', c[0], 112);
|
||||
// Mid tree layer
|
||||
Draw.hills(ctx, w, h, h * 0.6, 6, c[1], 113);
|
||||
Draw.trees(ctx, w, h, h * 0.68, 18, '#5C3A1E', c[2], 114);
|
||||
// Foreground
|
||||
Draw.hills(ctx, w, h, h * 0.8, 5, c[2], 115);
|
||||
Draw.trees(ctx, w, h, h * 0.85, 10, '#6B4226', c[3], 116);
|
||||
// Forest floor
|
||||
Draw.rect(ctx, 0, h * 0.88, w, h * 0.12, H.darken(c[0], 0.4));
|
||||
// Light rays
|
||||
var rng = H.seededRandom(117);
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.04 + Math.sin(t * 0.5) * 0.02;
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var rx = rng() * w;
|
||||
ctx.fillStyle = '#FFFFCC';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(rx, 0);
|
||||
ctx.lineTo(rx - 30, h * 0.7);
|
||||
ctx.lineTo(rx + 30, h * 0.7);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.restore();
|
||||
},
|
||||
particles: { type: 'fireflies', count: 20, color: '#CCFF66' }
|
||||
},
|
||||
|
||||
jungle: {
|
||||
meta: { id: 'nature_jungle', mood: 'adventurous', colors: ['#0D2B0D', '#1A4D1A', '#2D7A2D', '#55AA33'], tags: ['tropical', 'dense', 'lush'], description: 'Thick tropical jungle with hanging vines and humid air', compatibleMusicMoods: ['adventurous', 'tense', 'ambient'], recommendedFor: ['action', 'rpg', 'pet'] },
|
||||
colors: ['#0D2B0D', '#1A4D1A', '#2D7A2D', '#55AA33'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#2A4420', c[0], H.darken(c[0], 0.3)], 90);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.hills(ctx, w, h, h * 0.35, 10, c[1], 210);
|
||||
Draw.trees(ctx, w, h, h * 0.5, 30, '#3B2510', c[1], 211);
|
||||
// Vines
|
||||
var rng = H.seededRandom(212);
|
||||
ctx.strokeStyle = H.rgba(c[2], 0.6);
|
||||
ctx.lineWidth = 2;
|
||||
for (var i = 0; i < 12; i++) {
|
||||
var vx = rng() * w;
|
||||
var sway = Math.sin(t * 0.8 + i * 1.3) * 8;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(vx, 0);
|
||||
ctx.quadraticCurveTo(vx + sway, h * 0.2 + rng() * h * 0.15, vx + sway * 0.5, h * 0.3 + rng() * h * 0.2);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Large canopy leaves at top
|
||||
Draw.hills(ctx, w, h * 0.15, h * 0.02, 12, H.rgba(c[2], 0.5), 213);
|
||||
// Mid layer dense foliage
|
||||
Draw.trees(ctx, w, h, h * 0.7, 20, '#4B3520', c[2], 214);
|
||||
// Ground ferns
|
||||
Draw.hills(ctx, w, h, h * 0.85, 15, c[3], 215);
|
||||
Draw.rect(ctx, 0, h * 0.9, w, h * 0.1, H.darken(c[0], 0.5));
|
||||
},
|
||||
particles: { type: 'fireflies', count: 25, color: '#AAEE44' }
|
||||
},
|
||||
|
||||
desert: {
|
||||
meta: { id: 'nature_desert', mood: 'warm', colors: ['#F4A460', '#DAA06D', '#C2955A', '#8B6914'], tags: ['sand', 'hot', 'arid'], description: 'Rolling sand dunes under a blazing sun', compatibleMusicMoods: ['calm', 'epic', 'ambient'], recommendedFor: ['racing', 'action', 'rpg'] },
|
||||
colors: ['#F4A460', '#DAA06D', '#C2955A', '#8B6914'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#FFCC66', '#FF9933', c[0]], 90);
|
||||
// Sun
|
||||
var sunPulse = 1 + Math.sin(t * 0.3) * 0.03;
|
||||
Draw.glow(ctx, w * 0.75, h * 0.12, 100 * sunPulse, H.rgba('#FFEE88', 0.4));
|
||||
Draw.circle(ctx, w * 0.75, h * 0.12, 35, '#FFDD44');
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Far dunes
|
||||
Draw.hills(ctx, w, h, h * 0.45, 5, H.lighten(c[0], 0.15), 310);
|
||||
// Mid dunes
|
||||
Draw.hills(ctx, w, h, h * 0.6, 4, c[1], 311);
|
||||
// Near dunes
|
||||
Draw.hills(ctx, w, h, h * 0.75, 3, c[2], 312);
|
||||
// Ground
|
||||
Draw.rect(ctx, 0, h * 0.82, w, h * 0.18, c[3]);
|
||||
// Heat shimmer
|
||||
var rng = H.seededRandom(313);
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.03 + Math.sin(t * 2) * 0.02;
|
||||
for (var i = 0; i < 8; i++) {
|
||||
var sy = h * 0.45 + rng() * h * 0.15;
|
||||
ctx.strokeStyle = '#FFFFFF';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
for (var x = 0; x < w; x += 6) {
|
||||
var yy = sy + Math.sin(x * 0.04 + t * 3 + i) * 3;
|
||||
x === 0 ? ctx.moveTo(x, yy) : ctx.lineTo(x, yy);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.restore();
|
||||
// Cacti
|
||||
for (var j = 0; j < 4; j++) {
|
||||
var cx = rng() * w;
|
||||
var cy = h * 0.72 + rng() * h * 0.06;
|
||||
var ch = 15 + rng() * 25;
|
||||
Draw.rect(ctx, cx - 3, cy - ch, 6, ch, '#2D5A27');
|
||||
Draw.rect(ctx, cx + 3, cy - ch * 0.7, 10, 4, '#2D5A27');
|
||||
Draw.rect(ctx, cx + 9, cy - ch * 0.7, 4, -10, '#2D5A27');
|
||||
Draw.rect(ctx, cx - 13, cy - ch * 0.5, 10, 4, '#2D5A27');
|
||||
Draw.rect(ctx, cx - 13, cy - ch * 0.5, 4, -8, '#2D5A27');
|
||||
}
|
||||
},
|
||||
particles: { type: 'dust', count: 20, color: '#DDCC99' }
|
||||
},
|
||||
|
||||
mountains: {
|
||||
meta: { id: 'nature_mountains', mood: 'majestic', colors: ['#2C3E50', '#4A6B5A', '#7A9B6B', '#FFFFFF'], tags: ['peaks', 'alpine', 'grand'], description: 'Snow-capped mountain peaks under sweeping skies', compatibleMusicMoods: ['epic', 'calm', 'dreamy'], recommendedFor: ['rpg', 'sports', 'story'] },
|
||||
colors: ['#2C3E50', '#4A6B5A', '#7A9B6B', '#FFFFFF'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#6699CC', '#AAC4DD', '#DDEEFF'], 90);
|
||||
Draw.clouds(ctx, w, h, h * 0.1, 8, '#FFFFFF', 410);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Far mountains
|
||||
Draw.mountains(ctx, w, h, h * 0.45, 6, H.rgba(c[0], 0.6), 411);
|
||||
// Snow caps
|
||||
Draw.mountains(ctx, w, h, h * 0.42, 6, H.rgba(c[3], 0.25), 411);
|
||||
// Mid mountains
|
||||
Draw.mountains(ctx, w, h, h * 0.55, 5, c[0], 412);
|
||||
Draw.mountains(ctx, w, h, h * 0.52, 5, H.rgba(c[3], 0.35), 412);
|
||||
// Foothills
|
||||
Draw.hills(ctx, w, h, h * 0.7, 8, c[1], 413);
|
||||
Draw.hills(ctx, w, h, h * 0.8, 6, c[2], 414);
|
||||
// Valley floor
|
||||
Draw.rect(ctx, 0, h * 0.85, w, h * 0.15, H.darken(c[2], 0.2));
|
||||
// River
|
||||
ctx.strokeStyle = H.rgba('#5588BB', 0.5);
|
||||
ctx.lineWidth = 4;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(w * 0.3, h * 0.85);
|
||||
ctx.quadraticCurveTo(w * 0.5, h * 0.88, w * 0.7, h * 0.92);
|
||||
ctx.quadraticCurveTo(w * 0.85, h * 0.95, w, h * 0.93);
|
||||
ctx.stroke();
|
||||
},
|
||||
particles: { type: 'fog', count: 8, color: '#CCCCCC' }
|
||||
},
|
||||
|
||||
ocean: {
|
||||
meta: { id: 'nature_ocean', mood: 'serene', colors: ['#1A5276', '#2E86C1', '#5DADE2', '#AED6F1'], tags: ['water', 'waves', 'calm'], description: 'Vast ocean stretching to the horizon at sunset', compatibleMusicMoods: ['calm', 'dreamy', 'ambient'], recommendedFor: ['puzzle', 'story', 'creative'] },
|
||||
colors: ['#1A5276', '#2E86C1', '#5DADE2', '#AED6F1'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#FF8844', '#FFAA66', '#FFCC88', c[3]], 90);
|
||||
// Setting sun
|
||||
var sunY = h * 0.35 + Math.sin(t * 0.1) * 2;
|
||||
Draw.glow(ctx, w * 0.5, sunY, 120, H.rgba('#FFAA44', 0.4));
|
||||
Draw.circle(ctx, w * 0.5, sunY, 30, '#FFDD66');
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Horizon line
|
||||
Draw.rect(ctx, 0, h * 0.45, w, 2, H.rgba('#FFEECC', 0.3));
|
||||
// Ocean
|
||||
Draw.water(ctx, w, h, h * 0.45, c[1], 3 + Math.sin(t) * 1, 510);
|
||||
// Sun reflection on water
|
||||
var rng = H.seededRandom(511);
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.08 + Math.sin(t * 0.5) * 0.04;
|
||||
for (var i = 0; i < 15; i++) {
|
||||
var ry = h * 0.47 + i * ((h * 0.53) / 15);
|
||||
var rw = 20 + rng() * 40 - i * 1.5;
|
||||
var rx = w * 0.5 - rw / 2 + Math.sin(t * 1.5 + i * 0.8) * 10;
|
||||
Draw.rect(ctx, rx, ry, rw, 2, '#FFDDAA');
|
||||
}
|
||||
ctx.restore();
|
||||
// Distant clouds
|
||||
Draw.clouds(ctx, w, h, h * 0.15, 4, '#FFDDBB', 512);
|
||||
},
|
||||
particles: { type: 'fog', count: 6, color: '#AACCDD' }
|
||||
},
|
||||
|
||||
underwater: {
|
||||
meta: { id: 'nature_underwater', mood: 'mystical', colors: ['#0A2342', '#1A4B6E', '#2E86C1', '#48D1CC'], tags: ['deep', 'aquatic', 'blue'], description: 'Deep beneath the waves with shafts of sunlight', compatibleMusicMoods: ['dreamy', 'ambient', 'calm'], recommendedFor: ['puzzle', 'pet', 'creative'] },
|
||||
colors: ['#0A2342', '#1A4B6E', '#2E86C1', '#48D1CC'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, [c[3], c[2], c[1], c[0]], 90);
|
||||
// Light rays from surface
|
||||
var rng = H.seededRandom(610);
|
||||
ctx.save();
|
||||
for (var i = 0; i < 6; i++) {
|
||||
var rx = rng() * w;
|
||||
var sway = Math.sin(t * 0.4 + i * 1.5) * 15;
|
||||
ctx.fillStyle = H.rgba('#AADDFF', 0.03 + Math.sin(t * 0.3 + i) * 0.01);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(rx + sway, 0);
|
||||
ctx.lineTo(rx - 40 + sway * 0.5, h);
|
||||
ctx.lineTo(rx + 40 + sway * 0.5, h);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.restore();
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
var rng = H.seededRandom(611);
|
||||
// Seaweed
|
||||
for (var i = 0; i < 10; i++) {
|
||||
var sx = rng() * w;
|
||||
var sh = 40 + rng() * 80;
|
||||
var sway = Math.sin(t * 0.8 + i * 2) * 10;
|
||||
ctx.strokeStyle = H.rgba('#228844', 0.5 + rng() * 0.3);
|
||||
ctx.lineWidth = 3 + rng() * 3;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx, h);
|
||||
ctx.quadraticCurveTo(sx + sway, h - sh * 0.5, sx + sway * 1.3, h - sh);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Coral mounds
|
||||
for (var j = 0; j < 6; j++) {
|
||||
var cx = rng() * w;
|
||||
var cr = 15 + rng() * 30;
|
||||
var cc = H.pick(['#CC4466', '#FF7744', '#FFAA33', '#AA55CC']);
|
||||
Draw.circle(ctx, cx, h - cr * 0.5, cr, H.rgba(cc, 0.5));
|
||||
Draw.circle(ctx, cx + cr * 0.4, h - cr * 0.3, cr * 0.6, H.rgba(cc, 0.35));
|
||||
}
|
||||
// Fish silhouettes
|
||||
for (var k = 0; k < 8; k++) {
|
||||
var fx = (rng() * w + t * (10 + rng() * 30)) % (w + 60) - 30;
|
||||
var fy = h * 0.2 + rng() * h * 0.5;
|
||||
var fs = 4 + rng() * 8;
|
||||
ctx.fillStyle = H.rgba(c[3], 0.3 + rng() * 0.2);
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(fx, fy, fs * 2, fs, 0, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
// Tail
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(fx - fs * 2, fy);
|
||||
ctx.lineTo(fx - fs * 3, fy - fs * 0.8);
|
||||
ctx.lineTo(fx - fs * 3, fy + fs * 0.8);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
// Sandy bottom
|
||||
Draw.rect(ctx, 0, h * 0.92, w, h * 0.08, H.rgba('#C2B280', 0.25));
|
||||
},
|
||||
particles: { type: 'bubbles', count: 30, color: '#88CCEE' }
|
||||
},
|
||||
|
||||
waterfall: {
|
||||
meta: { id: 'nature_waterfall', mood: 'refreshing', colors: ['#1B4332', '#2D6A4F', '#52B788', '#B7E4C7'], tags: ['water', 'lush', 'dynamic'], description: 'A cascading waterfall in a lush green cliff', compatibleMusicMoods: ['calm', 'ambient', 'dreamy'], recommendedFor: ['puzzle', 'creative', 'story'] },
|
||||
colors: ['#1B4332', '#2D6A4F', '#52B788', '#B7E4C7'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#77AABB', '#99CCDD', c[2]], 90);
|
||||
Draw.clouds(ctx, w, h, h * 0.05, 3, '#FFFFFF', 710);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Cliff walls
|
||||
Draw.rect(ctx, 0, h * 0.15, w * 0.35, h * 0.85, c[0]);
|
||||
Draw.rect(ctx, w * 0.65, h * 0.15, w * 0.35, h * 0.85, c[0]);
|
||||
// Cliff vegetation
|
||||
Draw.hills(ctx, w * 0.35, h * 0.2, h * 0.15, 5, c[1], 711);
|
||||
ctx.save(); ctx.translate(w * 0.65, 0);
|
||||
Draw.hills(ctx, w * 0.35, h * 0.2, h * 0.15, 5, c[1], 712);
|
||||
ctx.restore();
|
||||
// Waterfall
|
||||
var rng = H.seededRandom(713);
|
||||
var fallX = w * 0.38, fallW = w * 0.24;
|
||||
for (var i = 0; i < 20; i++) {
|
||||
var fx = fallX + rng() * fallW;
|
||||
var fy = h * 0.15 + rng() * h * 0.65;
|
||||
var offset = (t * 80 + rng() * 200) % (h * 0.7);
|
||||
var wy = h * 0.15 + offset;
|
||||
ctx.strokeStyle = H.rgba('#FFFFFF', 0.1 + rng() * 0.2);
|
||||
ctx.lineWidth = 1 + rng() * 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(fx, wy);
|
||||
ctx.lineTo(fx + (rng() - 0.5) * 4, wy + 10 + rng() * 20);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Base glow
|
||||
Draw.fillGradient(ctx, w, h, [H.rgba(c[3], 0), H.rgba(c[3], 0), H.rgba('#FFFFFF', 0.15)], 90);
|
||||
// Pool at bottom
|
||||
Draw.water(ctx, w, h, h * 0.82, H.rgba('#3388AA', 0.6), 2, 714);
|
||||
// Mist
|
||||
Draw.glow(ctx, w * 0.5, h * 0.8, 100, H.rgba('#FFFFFF', 0.12 + Math.sin(t) * 0.04));
|
||||
// Foreground plants
|
||||
Draw.trees(ctx, w, h, h * 0.9, 6, '#3D2B1F', c[2], 715);
|
||||
},
|
||||
particles: { type: 'fog', count: 12, color: '#DDEEFF' }
|
||||
},
|
||||
|
||||
meadow: {
|
||||
meta: { id: 'nature_meadow', mood: 'joyful', colors: ['#4CAF50', '#81C784', '#A5D6A7', '#FFF59D'], tags: ['flowers', 'sunny', 'cheerful'], description: 'A sunny meadow with wildflowers and gentle breeze', compatibleMusicMoods: ['happy', 'calm', 'dreamy'], recommendedFor: ['pet', 'creative', 'story', 'puzzle'] },
|
||||
colors: ['#4CAF50', '#81C784', '#A5D6A7', '#FFF59D'],
|
||||
renderBase: function(ctx, w, h, c, Draw, t) {
|
||||
Draw.fillGradient(ctx, w, h, ['#55AADD', '#88CCEE', '#AADDEE'], 90);
|
||||
// Sun
|
||||
var pulse = 1 + Math.sin(t * 0.4) * 0.02;
|
||||
Draw.glow(ctx, w * 0.8, h * 0.1, 80 * pulse, H.rgba('#FFEE66', 0.4));
|
||||
Draw.circle(ctx, w * 0.8, h * 0.1, 28, '#FFEE44');
|
||||
Draw.clouds(ctx, w, h, h * 0.08, 6, '#FFFFFF', 810);
|
||||
},
|
||||
renderMid: function(ctx, w, h, c, Draw, t) {
|
||||
// Distant hills
|
||||
Draw.hills(ctx, w, h, h * 0.55, 5, H.darken(c[0], 0.15), 811);
|
||||
// Main meadow
|
||||
Draw.hills(ctx, w, h, h * 0.65, 8, c[0], 812);
|
||||
Draw.hills(ctx, w, h, h * 0.72, 6, c[1], 813);
|
||||
// Ground
|
||||
Draw.rect(ctx, 0, h * 0.78, w, h * 0.22, c[2]);
|
||||
// Flowers
|
||||
var rng = H.seededRandom(814);
|
||||
var flowerColors = ['#FF6B6B', '#FFD93D', '#C084FC', '#FF8FA3', '#FFFFFF'];
|
||||
for (var i = 0; i < 40; i++) {
|
||||
var fx = rng() * w;
|
||||
var fy = h * 0.68 + rng() * h * 0.25;
|
||||
var fc = flowerColors[Math.floor(rng() * flowerColors.length)];
|
||||
var sway = Math.sin(t * 1.2 + i * 0.8) * 2;
|
||||
// Stem
|
||||
ctx.strokeStyle = H.rgba('#338833', 0.5);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(fx, fy + 8);
|
||||
ctx.lineTo(fx + sway, fy);
|
||||
ctx.stroke();
|
||||
// Flower
|
||||
Draw.circle(ctx, fx + sway, fy, 2 + rng() * 2, fc);
|
||||
}
|
||||
// Butterflies
|
||||
for (var j = 0; j < 3; j++) {
|
||||
var bx = (rng() * w + Math.sin(t * 0.5 + j * 3) * 40);
|
||||
var by = h * 0.4 + rng() * h * 0.3 + Math.sin(t * 1.2 + j * 2) * 15;
|
||||
var wingFlap = Math.abs(Math.sin(t * 5 + j * 2)) * 4;
|
||||
var bc = H.pick(['#FFD700', '#FF69B4', '#87CEEB']);
|
||||
ctx.fillStyle = H.rgba(bc, 0.7);
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(bx - 3, by, wingFlap, 3, -0.3, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(bx + 3, by, wingFlap, 3, 0.3, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
Draw.circle(ctx, bx, by, 1, '#333333');
|
||||
}
|
||||
},
|
||||
particles: { type: 'leaves', count: 10, color: '#AEDD77' }
|
||||
}
|
||||
});
|
||||
|
||||
})(window.BackgroundEngine);
|
||||
Reference in New Issue
Block a user