UI Rework

This commit is contained in:
2026-01-24 21:30:08 +00:00
parent 4183d7f122
commit 1e8b7082a4
37 changed files with 4648 additions and 2754 deletions

View File

@@ -0,0 +1,189 @@
import type { DrawContext } from '../types';
export function drawCityBuildings(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const parallax = state.mouseX * 0.35;
const drawBuilding = (x: number, bWidth: number, bHeight: number, color: string, hasSpire: boolean = false) => {
const baseY = height * 0.8;
ctx.fillStyle = color;
ctx.fillRect(x + parallax, baseY - bHeight, bWidth, bHeight);
const gradient = ctx.createLinearGradient(x + parallax, 0, x + parallax + bWidth, 0);
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.1)');
gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0.05)');
ctx.fillStyle = gradient;
ctx.fillRect(x + parallax, baseY - bHeight, bWidth, bHeight);
ctx.fillStyle = 'rgba(255, 255, 200, 0.8)';
const windowCols = Math.floor(bWidth / 18);
const windowRows = Math.floor(bHeight / 25);
for (let row = 0; row < windowRows; row++) {
for (let col = 0; col < windowCols; col++) {
if (Math.random() > 0.15) {
ctx.fillStyle = Math.random() > 0.7 ? 'rgba(255, 255, 200, 0.9)' : 'rgba(200, 220, 255, 0.6)';
ctx.fillRect(
x + parallax + col * 18 + 5,
baseY - bHeight + row * 25 + 8,
10, 12
);
}
}
}
if (hasSpire) {
ctx.fillStyle = '#90A4AE';
ctx.beginPath();
ctx.moveTo(x + parallax + bWidth / 2, baseY - bHeight - 40);
ctx.lineTo(x + parallax + bWidth / 2 - 8, baseY - bHeight);
ctx.lineTo(x + parallax + bWidth / 2 + 8, baseY - bHeight);
ctx.closePath();
ctx.fill();
}
};
drawBuilding(width * 0.02, 55, height * 0.28, '#607D8B');
drawBuilding(width * 0.08, 70, height * 0.42, '#78909C', true);
drawBuilding(width * 0.18, 50, height * 0.32, '#546E7A');
drawBuilding(width * 0.25, 85, height * 0.55, '#455A64', true);
drawBuilding(width * 0.38, 60, height * 0.38, '#607D8B');
drawBuilding(width * 0.48, 75, height * 0.48, '#78909C', true);
drawBuilding(width * 0.58, 55, height * 0.35, '#546E7A');
drawBuilding(width * 0.68, 90, height * 0.52, '#455A64', true);
drawBuilding(width * 0.8, 65, height * 0.4, '#607D8B');
drawBuilding(width * 0.9, 50, height * 0.3, '#78909C');
}
export function drawStreet(dc: DrawContext): void {
const { ctx, width, height } = dc;
const time = Date.now() * 0.001;
ctx.fillStyle = '#424242';
ctx.fillRect(0, height * 0.82, width, height * 0.08);
ctx.strokeStyle = '#FFEB3B';
ctx.lineWidth = 3;
ctx.setLineDash([30, 20]);
ctx.beginPath();
ctx.moveTo(0, height * 0.86);
ctx.lineTo(width, height * 0.86);
ctx.stroke();
ctx.setLineDash([]);
const drawCar = (baseX: number, y: number, color: string, direction: number) => {
const x = ((baseX + time * 50 * direction) % (width + 100)) - 50;
ctx.fillStyle = color;
ctx.beginPath();
ctx.roundRect(x, y, 40, 15, 3);
ctx.fill();
ctx.fillStyle = color;
ctx.beginPath();
ctx.roundRect(x + 8, y - 10, 24, 12, 3);
ctx.fill();
ctx.fillStyle = '#81D4FA';
ctx.fillRect(x + 10, y - 8, 9, 8);
ctx.fillRect(x + 21, y - 8, 9, 8);
ctx.fillStyle = '#212121';
ctx.beginPath();
ctx.arc(x + 10, y + 15, 5, 0, Math.PI * 2);
ctx.arc(x + 30, y + 15, 5, 0, Math.PI * 2);
ctx.fill();
};
drawCar(width * 0.1, height * 0.83, '#E53935', 1);
drawCar(width * 0.5, height * 0.83, '#1E88E5', 1);
drawCar(width * 0.3, height * 0.87, '#43A047', -1);
drawCar(width * 0.8, height * 0.87, '#FDD835', -1);
}
export function drawAirplane(dc: DrawContext): void {
const { ctx, width, height, state } = dc;
const time = Date.now() * 0.0003;
const parallax = state.mouseX * 0.1;
const x = (time * width) % (width + 200) - 100;
const y = height * 0.15 + Math.sin(time * 5) * 10;
ctx.save();
ctx.translate(x + parallax, y);
ctx.fillStyle = '#ECEFF1';
ctx.beginPath();
ctx.ellipse(0, 0, 40, 8, 0, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.ellipse(45, 0, 12, 6, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#B0BEC5';
ctx.beginPath();
ctx.moveTo(-10, 0);
ctx.lineTo(-30, -35);
ctx.lineTo(10, -35);
ctx.lineTo(15, 0);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(-10, 0);
ctx.lineTo(-30, 35);
ctx.lineTo(10, 35);
ctx.lineTo(15, 0);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#E53935';
ctx.beginPath();
ctx.moveTo(-35, 0);
ctx.lineTo(-50, -20);
ctx.lineTo(-30, 0);
ctx.closePath();
ctx.fill();
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(-50, 0);
ctx.lineTo(-150, 3);
ctx.stroke();
ctx.restore();
}
export function drawParks(dc: DrawContext): void {
const { ctx, width, height } = dc;
ctx.fillStyle = '#81C784';
const parks = [
{ x: width * 0.05, y: height * 0.81, rx: 25, ry: 8 },
{ x: width * 0.35, y: height * 0.81, rx: 30, ry: 10 },
{ x: width * 0.75, y: height * 0.81, rx: 35, ry: 9 },
];
parks.forEach(p => {
ctx.beginPath();
ctx.ellipse(p.x, p.y, p.rx, p.ry, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#4CAF50';
ctx.beginPath();
ctx.arc(p.x - 10, p.y - 5, 8, 0, Math.PI * 2);
ctx.arc(p.x + 10, p.y - 3, 6, 0, Math.PI * 2);
ctx.fill();
});
}
export function drawCityScene(dc: DrawContext): void {
drawAirplane(dc);
drawCityBuildings(dc);
drawParks(dc);
drawStreet(dc);
}