Files
2026-04-30 02:14:25 +00:00

480 lines
24 KiB
JavaScript

// indoor.js — Indoor environment background themes
// Variants: laboratory, classroom, bedroom, kitchen, arcade, office, library, gym
(function(engine) {
if (!engine) return;
var D = engine.Draw, H = engine.helpers;
engine.registerTheme('indoor', {
laboratory: {
meta: { id: 'indoor_laboratory', mood: 'mysterious', colors: ['#1a1e2e', '#2a3040', '#0f6b5e', '#44eebb'], tags: ['science', 'lab', 'tech', 'glow'], description: 'Dark science lab with glowing equipment and bubbling vials', compatibleMusicMoods: ['mysterious', 'tense', 'ambient'], recommendedFor: ['puzzle', 'trivia', 'rpg'] },
colors: ['#1a1e2e', '#2a3040', '#0f6b5e', '#44eebb'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
Draw.rect(ctx, 0, h * 0.75, w, h * 0.25, H.darken(c[0], 0.3));
ctx.strokeStyle = H.rgba(c[2], 0.15);
ctx.lineWidth = 1;
for (var i = 0; i < w; i += 60) { ctx.beginPath(); ctx.moveTo(i, 0); ctx.lineTo(i, h); ctx.stroke(); }
for (var j = 0; j < h; j += 60) { ctx.beginPath(); ctx.moveTo(0, j); ctx.lineTo(w, j); ctx.stroke(); }
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(101);
// Lab benches
Draw.rect(ctx, w * 0.05, h * 0.72, w * 0.4, h * 0.04, '#3a3a4a');
Draw.rect(ctx, w * 0.55, h * 0.72, w * 0.4, h * 0.04, '#3a3a4a');
// Beakers and vials
for (var i = 0; i < 6; i++) {
var bx = w * 0.08 + i * w * 0.07;
var bh = 20 + rng() * 25;
var glow = 0.4 + Math.sin(t * (1.5 + rng()) + i) * 0.3;
Draw.rect(ctx, bx, h * 0.72 - bh, 12, bh, H.rgba(c[3], glow));
Draw.rect(ctx, bx - 2, h * 0.72 - bh, 16, 3, H.rgba('#FFFFFF', 0.2));
}
// Glowing tanks
for (var j = 0; j < 3; j++) {
var tx = w * 0.58 + j * w * 0.13;
var pulse = 0.15 + Math.sin(t * 0.8 + j * 2) * 0.1;
Draw.rect(ctx, tx, h * 0.45, 30, h * 0.27, H.rgba(c[2], pulse));
Draw.rect(ctx, tx - 2, h * 0.44, 34, 4, '#555566');
Draw.rect(ctx, tx - 2, h * 0.72, 34, 4, '#555566');
Draw.glow(ctx, tx + 15, h * 0.58, 35, c[3]);
}
// Ceiling pipes
for (var p = 0; p < 4; p++) {
var py = h * 0.05 + p * 18;
Draw.rect(ctx, 0, py, w, 6, H.rgba('#556677', 0.3));
}
// Blinking lights on wall
for (var k = 0; k < 8; k++) {
var lx = w * 0.1 + rng() * w * 0.8;
var ly = h * 0.1 + rng() * h * 0.3;
var on = Math.sin(t * (2 + rng() * 3) + k * 1.7) > 0.3;
Draw.circle(ctx, lx, ly, 3, on ? c[3] : H.rgba(c[2], 0.2));
if (on) Draw.glow(ctx, lx, ly, 12, c[3]);
}
},
particles: { type: 'bubbles', count: 15, color: '#44eebb' }
},
classroom: {
meta: { id: 'indoor_classroom', mood: 'cheerful', colors: ['#f5f0e0', '#d4c9a8', '#5b8c5a', '#8b5e3c'], tags: ['school', 'learning', 'education', 'cozy'], description: 'Bright classroom with chalkboard, desks, and warm sunlight', compatibleMusicMoods: ['cheerful', 'calm', 'upbeat'], recommendedFor: ['trivia', 'puzzle', 'story'] },
colors: ['#f5f0e0', '#d4c9a8', '#5b8c5a', '#8b5e3c'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], H.darken(c[0], 0.05)], 90);
Draw.rect(ctx, 0, h * 0.78, w, h * 0.22, c[1]);
// Baseboard
Draw.rect(ctx, 0, h * 0.76, w, h * 0.03, H.darken(c[3], 0.2));
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(202);
// Chalkboard
Draw.rect(ctx, w * 0.15, h * 0.15, w * 0.7, h * 0.35, '#2a4a2a');
Draw.rect(ctx, w * 0.14, h * 0.14, w * 0.72, h * 0.37, 'transparent');
ctx.strokeStyle = c[3]; ctx.lineWidth = 4;
ctx.strokeRect(w * 0.14, h * 0.14, w * 0.72, h * 0.37);
// Chalk text squiggles
ctx.strokeStyle = H.rgba('#FFFFFF', 0.3); ctx.lineWidth = 1;
for (var i = 0; i < 5; i++) {
ctx.beginPath();
var ly = h * 0.22 + i * h * 0.06;
ctx.moveTo(w * 0.2, ly);
for (var x = w * 0.2; x < w * 0.75; x += 8) {
ctx.lineTo(x, ly + (rng() - 0.5) * 3);
}
ctx.stroke();
}
// Desks
for (var d = 0; d < 3; d++) {
var dy = h * 0.6 + d * h * 0.08;
for (var dx = 0; dx < 4; dx++) {
var xx = w * 0.12 + dx * w * 0.22;
Draw.rect(ctx, xx, dy, w * 0.16, h * 0.025, c[3]);
Draw.rect(ctx, xx + 5, dy + h * 0.025, 4, h * 0.04, H.darken(c[3], 0.3));
Draw.rect(ctx, xx + w * 0.14, dy + h * 0.025, 4, h * 0.04, H.darken(c[3], 0.3));
}
}
// Window with sunlight
Draw.rect(ctx, w * 0.02, h * 0.15, w * 0.08, h * 0.35, '#88bbdd');
ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 3;
ctx.strokeRect(w * 0.02, h * 0.15, w * 0.08, h * 0.35);
ctx.beginPath(); ctx.moveTo(w * 0.06, h * 0.15); ctx.lineTo(w * 0.06, h * 0.5); ctx.stroke();
var sunAlpha = 0.05 + Math.sin(t * 0.3) * 0.02;
ctx.fillStyle = H.rgba('#FFE488', sunAlpha);
ctx.beginPath(); ctx.moveTo(w * 0.1, h * 0.15); ctx.lineTo(w * 0.35, h * 0.78);
ctx.lineTo(w * 0.1, h * 0.78); ctx.closePath(); ctx.fill();
// Clock
var cx = w * 0.9, cy = h * 0.12;
Draw.circle(ctx, cx, cy, 18, '#FFFFFF');
ctx.strokeStyle = '#333'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.arc(cx, cy, 18, 0, Math.PI * 2); ctx.stroke();
var angle = t * 0.1;
ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(cx + Math.cos(angle) * 12, cy + Math.sin(angle) * 12); ctx.stroke();
},
particles: { type: 'dust', count: 20, color: '#DDC888' }
},
bedroom: {
meta: { id: 'indoor_bedroom', mood: 'cozy', colors: ['#2a1f3d', '#3d2b5a', '#e8a87c', '#ffd166'], tags: ['cozy', 'night', 'home', 'warm'], description: 'Cozy bedroom at night with warm lamp glow and string lights', compatibleMusicMoods: ['calm', 'dreamy', 'ambient'], recommendedFor: ['story', 'creative', 'pet'] },
colors: ['#2a1f3d', '#3d2b5a', '#e8a87c', '#ffd166'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
Draw.rect(ctx, 0, h * 0.8, w, h * 0.2, H.darken(c[1], 0.3));
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(303);
// Window with moonlight
Draw.rect(ctx, w * 0.6, h * 0.1, w * 0.2, h * 0.3, '#1a1a3e');
Draw.circle(ctx, w * 0.72, h * 0.18, 15, '#dde8ff');
Draw.glow(ctx, w * 0.72, h * 0.18, 40, '#aabbee');
ctx.strokeStyle = H.rgba('#FFFFFF', 0.3); ctx.lineWidth = 3;
ctx.strokeRect(w * 0.6, h * 0.1, w * 0.2, h * 0.3);
ctx.beginPath(); ctx.moveTo(w * 0.7, h * 0.1); ctx.lineTo(w * 0.7, h * 0.4); ctx.stroke();
// Bed
Draw.rect(ctx, w * 0.05, h * 0.55, w * 0.45, h * 0.25, '#6b4f7a');
Draw.rect(ctx, w * 0.05, h * 0.55, w * 0.12, h * 0.22, '#7a5f8a');
Draw.rect(ctx, w * 0.05, h * 0.5, w * 0.45, h * 0.06, H.darken('#6b4f7a', 0.3));
// Lamp with warm glow
var lampX = w * 0.88, lampY = h * 0.45;
Draw.rect(ctx, lampX - 3, lampY, 6, h * 0.35, '#666');
Draw.polygon(ctx, lampX, lampY - 5, 18, 3, c[2], -Math.PI / 2);
var lampGlow = 0.2 + Math.sin(t * 0.5) * 0.05;
Draw.glow(ctx, lampX, lampY - 10, 80, c[3]);
ctx.fillStyle = H.rgba(c[3], lampGlow);
ctx.beginPath(); ctx.moveTo(lampX - 40, lampY); ctx.lineTo(lampX + 40, lampY);
ctx.lineTo(lampX + 80, h * 0.8); ctx.lineTo(lampX - 80, h * 0.8); ctx.closePath(); ctx.fill();
// String lights across top
ctx.strokeStyle = H.rgba('#FFFFFF', 0.1); ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(0, h * 0.05);
for (var x = 0; x < w; x += 5) { ctx.lineTo(x, h * 0.05 + Math.sin(x * 0.02) * 10); }
ctx.stroke();
for (var i = 0; i < 12; i++) {
var lx = w * 0.05 + i * w * 0.08;
var ly = h * 0.05 + Math.sin(lx * 0.02) * 10;
var flicker = 0.5 + Math.sin(t * 2 + i * 1.3) * 0.3;
var lc = H.pick(['#ff6b6b', '#ffd166', '#06d6a0', '#118ab2', '#ef476f']);
Draw.circle(ctx, lx, ly + 5, 4, H.rgba(lc, flicker));
Draw.glow(ctx, lx, ly + 5, 12, lc);
}
// Bookshelf
Draw.rect(ctx, w * 0.55, h * 0.5, w * 0.15, h * 0.3, '#5a3e2b');
for (var s = 0; s < 3; s++) {
Draw.rect(ctx, w * 0.55, h * 0.5 + s * h * 0.1, w * 0.15, 3, '#4a2e1b');
for (var b = 0; b < 4; b++) {
var bw = 6 + rng() * 8;
var bc = H.pick(['#cc4444', '#4477bb', '#44aa66', '#ddaa33', '#8855aa']);
Draw.rect(ctx, w * 0.56 + b * (bw + 3), h * 0.5 + s * h * 0.1 + 4, bw, h * 0.09, bc);
}
}
},
particles: { type: 'fireflies', count: 8, color: '#ffd166' }
},
kitchen: {
meta: { id: 'indoor_kitchen', mood: 'warm', colors: ['#fff8e7', '#f0d9a0', '#c97b3a', '#8b4513'], tags: ['cooking', 'home', 'warm', 'food'], description: 'Bright kitchen with checkered floor, cabinets, and warm appliance glow', compatibleMusicMoods: ['cheerful', 'upbeat', 'calm'], recommendedFor: ['creative', 'pet', 'puzzle'] },
colors: ['#fff8e7', '#f0d9a0', '#c97b3a', '#8b4513'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], H.darken(c[0], 0.05)], 90);
// Checkered floor
var tileSize = 30;
for (var ty = h * 0.75; ty < h; ty += tileSize) {
for (var tx = 0; tx < w; tx += tileSize) {
var checker = ((Math.floor(tx / tileSize) + Math.floor(ty / tileSize)) % 2 === 0);
Draw.rect(ctx, tx, ty, tileSize, tileSize, checker ? '#e8e0d0' : '#c8b8a0');
}
}
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(404);
// Upper cabinets
for (var i = 0; i < 4; i++) {
var cx = w * 0.05 + i * w * 0.24;
Draw.rect(ctx, cx, h * 0.08, w * 0.2, h * 0.2, c[2]);
Draw.rect(ctx, cx + 3, h * 0.1, w * 0.2 - 6, h * 0.16, H.lighten(c[2], 0.15));
Draw.circle(ctx, cx + w * 0.1, h * 0.18, 3, '#brass');
Draw.circle(ctx, cx + w * 0.1, h * 0.18, 3, '#aa8844');
}
// Counter
Draw.rect(ctx, 0, h * 0.42, w, h * 0.04, '#ddd0bb');
Draw.rect(ctx, 0, h * 0.46, w, h * 0.29, c[3]);
// Stove
var sx = w * 0.35;
Draw.rect(ctx, sx, h * 0.32, w * 0.2, h * 0.1, '#444');
for (var b = 0; b < 4; b++) {
var bx = sx + w * 0.025 + b * w * 0.045;
var burnerGlow = Math.sin(t * 1.5 + b * 0.8) > 0.5 ? 0.4 : 0;
Draw.circle(ctx, bx, h * 0.37, 8, H.rgba('#ff4400', burnerGlow));
Draw.circle(ctx, bx, h * 0.37, 12, '#555');
ctx.strokeStyle = '#666'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.arc(bx, h * 0.37, 10, 0, Math.PI * 2); ctx.stroke();
}
// Fridge
Draw.rect(ctx, w * 0.82, h * 0.15, w * 0.15, h * 0.6, '#d8d8d8');
Draw.rect(ctx, w * 0.83, h * 0.16, w * 0.13, h * 0.3, '#e8e8e8');
Draw.rect(ctx, w * 0.83, h * 0.48, w * 0.13, h * 0.25, '#e8e8e8');
Draw.rect(ctx, w * 0.95, h * 0.28, 3, 20, '#999');
Draw.rect(ctx, w * 0.95, h * 0.58, 3, 20, '#999');
// Sink
Draw.rect(ctx, w * 0.1, h * 0.35, w * 0.15, h * 0.07, '#bbb');
Draw.rect(ctx, w * 0.15, h * 0.3, 4, h * 0.05, '#999');
// Hanging pots
for (var p = 0; p < 3; p++) {
var px = w * 0.62 + p * w * 0.06;
var sway = Math.sin(t * 0.3 + p) * 2;
ctx.strokeStyle = '#777'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(px, h * 0.08); ctx.lineTo(px + sway, h * 0.14); ctx.stroke();
Draw.circle(ctx, px + sway, h * 0.16, 10 + p * 2, H.pick(['#884422', '#666', '#aa6633']));
}
// Window light
Draw.rect(ctx, w * 0.03, h * 0.08, w * 0.12, h * 0.18, '#aaddff');
ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 3;
ctx.strokeRect(w * 0.03, h * 0.08, w * 0.12, h * 0.18);
},
particles: { type: 'dust', count: 12, color: '#EECC88' }
},
arcade: {
meta: { id: 'indoor_arcade', mood: 'energetic', colors: ['#0d0d1a', '#1a0a2e', '#ff00ff', '#00ffff'], tags: ['neon', 'retro', 'gaming', 'dark'], description: 'Dark arcade with neon-lit cabinets, glowing screens, and retro vibes', compatibleMusicMoods: ['energetic', 'retro', 'electronic'], recommendedFor: ['action', 'racing', 'sports'] },
colors: ['#0d0d1a', '#1a0a2e', '#ff00ff', '#00ffff'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
// Dark reflective floor
Draw.rect(ctx, 0, h * 0.8, w, h * 0.2, '#0a0a15');
Draw.grid(ctx, w, h * 0.2, 40, H.rgba(c[2], 0.05), 1);
// Neon strip on ceiling
var neonPulse = 0.3 + Math.sin(t * 1.2) * 0.15;
Draw.rect(ctx, 0, 0, w, 4, H.rgba(c[2], neonPulse));
Draw.rect(ctx, 0, h * 0.8, w, 2, H.rgba(c[3], neonPulse * 0.6));
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(505);
// Arcade cabinets
for (var i = 0; i < 6; i++) {
var ax = w * 0.05 + i * w * 0.155;
var cabColor = H.pick(['#222233', '#1a1a2e', '#2a1a2e']);
Draw.rect(ctx, ax, h * 0.3, w * 0.1, h * 0.5, cabColor);
// Screen glow
var screenColor = H.pick([c[2], c[3], '#44ff44', '#ffaa00']);
var flicker = 0.5 + Math.sin(t * (3 + rng()) + i * 2) * 0.2;
Draw.rect(ctx, ax + 5, h * 0.33, w * 0.1 - 10, h * 0.18, H.rgba(screenColor, flicker));
Draw.glow(ctx, ax + w * 0.05, h * 0.42, 40, screenColor);
// Control panel
Draw.rect(ctx, ax + 3, h * 0.55, w * 0.1 - 6, h * 0.08, '#333');
// Joystick
Draw.circle(ctx, ax + w * 0.03, h * 0.59, 4, '#888');
// Buttons
for (var b = 0; b < 3; b++) {
Draw.circle(ctx, ax + w * 0.06 + b * 10, h * 0.59, 3, H.pick(['#ff3333', '#33ff33', '#3333ff']));
}
}
// Neon signs on wall
ctx.font = 'bold 16px monospace';
var signGlow = 0.6 + Math.sin(t * 2) * 0.3;
ctx.fillStyle = H.rgba(c[2], signGlow);
ctx.shadowColor = c[2]; ctx.shadowBlur = 15;
ctx.fillText('PLAY', w * 0.15, h * 0.15);
ctx.fillStyle = H.rgba(c[3], signGlow);
ctx.shadowColor = c[3];
ctx.fillText('HIGH SCORE', w * 0.55, h * 0.15);
ctx.shadowBlur = 0;
// Floor reflections
for (var r = 0; r < 6; r++) {
var rx = w * 0.05 + r * w * 0.155 + w * 0.05;
var refColor = H.pick([c[2], c[3], '#44ff44']);
Draw.glow(ctx, rx, h * 0.85, 25, refColor);
}
// Scanlines
Draw.scanlines(ctx, w, h, 3, H.rgba('#000000', 0.08));
},
particles: { type: 'sparkles', count: 20, color: '#ff00ff' }
},
office: {
meta: { id: 'indoor_office', mood: 'focused', colors: ['#e8e4dc', '#c5bfb2', '#4a6fa5', '#2c3e50'], tags: ['work', 'modern', 'clean', 'professional'], description: 'Modern office with monitor glow, clean desks, and large windows', compatibleMusicMoods: ['calm', 'focused', 'ambient'], recommendedFor: ['puzzle', 'trivia', 'creative'] },
colors: ['#e8e4dc', '#c5bfb2', '#4a6fa5', '#2c3e50'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], H.darken(c[0], 0.08)], 90);
Draw.rect(ctx, 0, h * 0.8, w, h * 0.2, '#b0a898');
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(606);
// Large windows
for (var i = 0; i < 3; i++) {
var wx = w * 0.05 + i * w * 0.32;
Draw.rect(ctx, wx, h * 0.05, w * 0.25, h * 0.4, '#aaccee');
ctx.strokeStyle = '#ddd'; ctx.lineWidth = 4;
ctx.strokeRect(wx, h * 0.05, w * 0.25, h * 0.4);
ctx.beginPath(); ctx.moveTo(wx + w * 0.125, h * 0.05); ctx.lineTo(wx + w * 0.125, h * 0.45); ctx.stroke();
// Sky through window
Draw.circle(ctx, wx + w * 0.18, h * 0.15, 8, '#fff8dd');
}
// Desks with monitors
for (var d = 0; d < 3; d++) {
var dx = w * 0.08 + d * w * 0.32;
// Desk
Draw.rect(ctx, dx, h * 0.6, w * 0.22, h * 0.03, '#8b7355');
Draw.rect(ctx, dx + 5, h * 0.63, 4, h * 0.17, '#7a6245');
Draw.rect(ctx, dx + w * 0.19, h * 0.63, 4, h * 0.17, '#7a6245');
// Monitor
var monX = dx + w * 0.05;
Draw.rect(ctx, monX, h * 0.48, w * 0.12, h * 0.1, '#222');
var screenGlow = 0.6 + Math.sin(t * 0.5 + d) * 0.15;
Draw.rect(ctx, monX + 3, h * 0.49, w * 0.12 - 6, h * 0.08, H.rgba(c[2], screenGlow));
Draw.rect(ctx, monX + w * 0.055, h * 0.58, 6, h * 0.02, '#333');
Draw.rect(ctx, monX + w * 0.035, h * 0.598, w * 0.05, 3, '#333');
// Keyboard
Draw.rect(ctx, dx + w * 0.04, h * 0.585, w * 0.08, h * 0.012, '#444');
}
// Ceiling lights
for (var l = 0; l < 4; l++) {
var lx = w * 0.12 + l * w * 0.23;
Draw.rect(ctx, lx, 0, w * 0.12, 6, '#eee');
var lightFlicker = 0.12 + Math.sin(t * 0.3 + l * 0.5) * 0.03;
ctx.fillStyle = H.rgba('#FFFFFF', lightFlicker);
ctx.beginPath(); ctx.moveTo(lx, 6); ctx.lineTo(lx + w * 0.12, 6);
ctx.lineTo(lx + w * 0.18, h * 0.5); ctx.lineTo(lx - w * 0.06, h * 0.5); ctx.closePath(); ctx.fill();
}
// Plant in corner
Draw.rect(ctx, w * 0.92, h * 0.6, 14, h * 0.2, '#8b6914');
Draw.circle(ctx, w * 0.928, h * 0.55, 20, '#3a7a3a');
Draw.circle(ctx, w * 0.94, h * 0.5, 14, '#4a8a4a');
Draw.circle(ctx, w * 0.916, h * 0.48, 12, '#3a7a3a');
},
particles: { type: 'dust', count: 10, color: '#DDDDCC' }
},
library: {
meta: { id: 'indoor_library', mood: 'serene', colors: ['#2c1810', '#4a3020', '#c4956a', '#f4e4c1'], tags: ['books', 'quiet', 'knowledge', 'wood'], description: 'Grand library with towering bookshelves, warm wood, and reading lamps', compatibleMusicMoods: ['calm', 'serene', 'classical'], recommendedFor: ['story', 'trivia', 'puzzle', 'rpg'] },
colors: ['#2c1810', '#4a3020', '#c4956a', '#f4e4c1'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [H.darken(c[0], 0.2), c[0]], 90);
Draw.rect(ctx, 0, h * 0.85, w, h * 0.15, H.darken(c[1], 0.3));
// Wooden floor planks
for (var p = 0; p < 12; p++) {
var px = p * (w / 12);
ctx.strokeStyle = H.rgba('#000', 0.1);
ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(px, h * 0.85); ctx.lineTo(px, h); ctx.stroke();
}
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(707);
var bookColors = ['#8b2500', '#2e5090', '#1a6030', '#8b6914', '#6a1b6a', '#cc5533', '#336677'];
// Tall bookshelves on sides
for (var side = 0; side < 2; side++) {
var sx = side === 0 ? 0 : w * 0.78;
var sw = w * 0.22;
Draw.rect(ctx, sx, h * 0.02, sw, h * 0.83, c[1]);
// Shelves
for (var sh = 0; sh < 7; sh++) {
var sy = h * 0.05 + sh * h * 0.115;
Draw.rect(ctx, sx, sy + h * 0.1, sw, 4, H.darken(c[1], 0.2));
// Books
var bx = sx + 5;
while (bx < sx + sw - 8) {
var bw = 5 + rng() * 10;
var bh = h * 0.08 + rng() * h * 0.02;
var bc = bookColors[Math.floor(rng() * bookColors.length)];
Draw.rect(ctx, bx, sy + h * 0.1 - bh, bw, bh, bc);
bx += bw + 1;
}
}
}
// Center reading area
Draw.rect(ctx, w * 0.35, h * 0.65, w * 0.3, h * 0.04, c[2]);
Draw.rect(ctx, w * 0.4, h * 0.69, 5, h * 0.16, H.darken(c[2], 0.3));
Draw.rect(ctx, w * 0.58, h * 0.69, 5, h * 0.16, H.darken(c[2], 0.3));
// Open book on table
Draw.rect(ctx, w * 0.44, h * 0.62, w * 0.06, h * 0.03, c[3]);
Draw.rect(ctx, w * 0.5, h * 0.62, w * 0.06, h * 0.03, H.darken(c[3], 0.05));
// Reading lamps
for (var l = 0; l < 2; l++) {
var lx = w * 0.38 + l * w * 0.24;
Draw.rect(ctx, lx, h * 0.5, 3, h * 0.15, '#886644');
var lampGlow = 0.25 + Math.sin(t * 0.4 + l * Math.PI) * 0.08;
Draw.polygon(ctx, lx + 1, h * 0.49, 14, 3, '#aa8855', -Math.PI / 2);
Draw.glow(ctx, lx + 1, h * 0.47, 50, '#ffcc66');
ctx.fillStyle = H.rgba('#ffdd88', lampGlow);
ctx.beginPath();
ctx.moveTo(lx - 18, h * 0.5); ctx.lineTo(lx + 20, h * 0.5);
ctx.lineTo(lx + 40, h * 0.85); ctx.lineTo(lx - 38, h * 0.85);
ctx.closePath(); ctx.fill();
}
// Arched window in back center
var awx = w * 0.4, awy = h * 0.08, aww = w * 0.2, awh = h * 0.35;
Draw.rect(ctx, awx, awy + awh * 0.3, aww, awh * 0.7, '#334466');
ctx.fillStyle = '#334466';
ctx.beginPath(); ctx.arc(awx + aww / 2, awy + awh * 0.3, aww / 2, Math.PI, 0); ctx.fill();
ctx.strokeStyle = c[2]; ctx.lineWidth = 4;
ctx.beginPath(); ctx.arc(awx + aww / 2, awy + awh * 0.3, aww / 2, Math.PI, 0); ctx.stroke();
ctx.strokeRect(awx, awy + awh * 0.3, aww, awh * 0.7);
// Moonlight through window
Draw.glow(ctx, awx + aww / 2, awy + awh * 0.3, 60, '#6688aa');
},
particles: { type: 'dust', count: 15, color: '#CCBB88' }
},
gym: {
meta: { id: 'indoor_gym', mood: 'energetic', colors: ['#1a1a24', '#2a2a3a', '#ff4444', '#ff8800'], tags: ['fitness', 'sports', 'energy', 'active'], description: 'Modern gym with equipment silhouettes, rubber floor, and bright overhead lights', compatibleMusicMoods: ['energetic', 'intense', 'upbeat'], recommendedFor: ['action', 'sports', 'racing'] },
colors: ['#1a1a24', '#2a2a3a', '#ff4444', '#ff8800'],
renderBase: function(ctx, w, h, c, Draw, t) {
Draw.fillGradient(ctx, w, h, [c[0], c[1]], 90);
// Rubber floor with subtle texture
Draw.rect(ctx, 0, h * 0.78, w, h * 0.22, '#222230');
var rng = H.seededRandom(808);
for (var i = 0; i < 40; i++) {
Draw.circle(ctx, rng() * w, h * 0.78 + rng() * h * 0.22, 1, H.rgba('#333344', 0.5));
}
},
renderMid: function(ctx, w, h, c, Draw, t) {
var rng = H.seededRandom(809);
// Wall mirror
Draw.rect(ctx, w * 0.1, h * 0.1, w * 0.8, h * 0.45, H.rgba('#445566', 0.15));
ctx.strokeStyle = H.rgba('#666', 0.3); ctx.lineWidth = 3;
ctx.strokeRect(w * 0.1, h * 0.1, w * 0.8, h * 0.45);
// Dumbbells rack
for (var d = 0; d < 6; d++) {
var dx = w * 0.05 + d * w * 0.05;
var dy = h * 0.7;
Draw.rect(ctx, dx, dy, 8, 4, '#555');
Draw.circle(ctx, dx - 2, dy + 2, 5, '#444');
Draw.circle(ctx, dx + 10, dy + 2, 5, '#444');
}
// Bench press
Draw.rect(ctx, w * 0.55, h * 0.65, w * 0.15, h * 0.02, '#444');
Draw.rect(ctx, w * 0.57, h * 0.67, 4, h * 0.11, '#555');
Draw.rect(ctx, w * 0.68, h * 0.67, 4, h * 0.11, '#555');
// Barbell
Draw.rect(ctx, w * 0.5, h * 0.6, w * 0.25, 3, '#888');
Draw.rect(ctx, w * 0.5, h * 0.585, 8, 18, '#666');
Draw.rect(ctx, w * 0.73, h * 0.585, 8, 18, '#666');
// Treadmill
Draw.rect(ctx, w * 0.8, h * 0.55, w * 0.12, h * 0.23, '#333');
Draw.rect(ctx, w * 0.81, h * 0.63, w * 0.1, h * 0.13, '#222');
var beltMove = (t * 2) % 1;
for (var s = 0; s < 6; s++) {
var sy = h * 0.63 + (s / 6 + beltMove / 6) * h * 0.13;
if (sy < h * 0.76) Draw.rect(ctx, w * 0.81, sy, w * 0.1, 1, H.rgba('#444', 0.5));
}
// Overhead lights
for (var l = 0; l < 5; l++) {
var lx = w * 0.1 + l * w * 0.2;
Draw.rect(ctx, lx, 0, w * 0.08, 8, '#eee');
var intensity = 0.08 + Math.sin(t * 0.2 + l * 0.3) * 0.02;
ctx.fillStyle = H.rgba('#FFFFFF', intensity);
ctx.beginPath(); ctx.moveTo(lx, 8); ctx.lineTo(lx + w * 0.08, 8);
ctx.lineTo(lx + w * 0.14, h * 0.78); ctx.lineTo(lx - w * 0.06, h * 0.78);
ctx.closePath(); ctx.fill();
}
// Red accent stripe on wall
var stripeGlow = 0.6 + Math.sin(t * 0.8) * 0.2;
Draw.rect(ctx, 0, h * 0.55, w, 4, H.rgba(c[2], stripeGlow));
// Motivational poster (abstract rectangle)
Draw.rect(ctx, w * 0.38, h * 0.15, w * 0.12, h * 0.15, '#333');
Draw.rect(ctx, w * 0.39, h * 0.16, w * 0.1, h * 0.13, c[2]);
},
particles: { type: 'dust', count: 8, color: '#887766' }
}
});
})(window.BackgroundEngine);