<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hello, world</title>
</head>
<body>
<main>
<h1>Hello, world.</h1>
<p>Every good idea starts somewhere.</p>
</main>
</body>
</html>
<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<title>Metro Dash 3D</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
background: #071425;
color: white;
font-family: Arial, sans-serif;
text-align: center;
overflow: hidden;
}
#game {
display: block;
width: 100%;
height: 100dvh;
touch-action: none;
}
#hud {
position: fixed;
top: 15px;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
pointer-events: none;
text-shadow: 0 2px 5px #000;
font-weight: bold;
font-size: 18px;
}
#help {
position: fixed;
top: 65px;
left: 0;
width: 100%;
font-size: 12px;
color: #d9f5ff;
pointer-events: none;
}
#menu {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #06102099;
}
.panel {
width: min(90%, 350px);
padding: 25px;
background: #102d49ee;
border: 2px solid #49e5ff;
border-radius: 22px;
box-shadow: 0 0 35px #00bfff55;
}
h1 {
font-size: 34px;
margin: 0 0 10px;
color: #61f3ff;
}
p {
line-height: 1.6;
}
button {
border: 0;
border-radius: 14px;
background: #24d6e9;
color: #052034;
font-weight: bold;
font-size: 17px;
padding: 14px 22px;
cursor: pointer;
}
#controls {
position: fixed;
bottom: 20px;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
pointer-events: none;
}
#controls button {
pointer-events: auto;
width: 65px;
height: 58px;
padding: 0;
background: #163b5cdd;
color: white;
border: 1px solid #8cefff;
font-size: 23px;
touch-action: manipulation;
}
#jump {
background: #b64cffdd !important;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="hud">
<div>⭐ SCORE <span id="score">0</span></div>
<div>🪙 <span id="coins">0</span></div>
</div>
<div id="help">← → लेन बदलो | SPACE कूदो | ↓ स्लाइड</div>
<div id="menu">
<div class="panel">
<h1>METRO DASH</h1>
<p id="message">🏃 दौड़ो, सिक्के इकट्ठा करो और ट्रेनों से बचो!</p>
<p>← → मूव • SPACE जंप</p>
<button id="start">▶ PLAY NOW</button>
</div>
</div>
<div id="controls">
<button id="left">◀</button>
<button id="jump">⬆</button>
<button id="right">▶</button>
<button id="slide">⬇</button>
</div>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const menu = document.getElementById("menu");
const scoreEl = document.getElementById("score");
const coinsEl = document.getElementById("coins");
let W, H, dpr, horizon;
let running = false,
over = false;
let lane = 0,
jump = 0,
slide = 0,
vy = 0;
let score = 0,
coins = 0,
speed = 0.38;
let objects = [],
spawn = 0,
last = 0,
time = 0;
let best = Number(localStorage.getItem("metroBest") || 0);
function resize() {
dpr = Math.min(devicePixelRatio || 1, 2);
W = innerWidth;
H = innerHeight;
canvas.width = W * dpr;
canvas.height = H * dpr;
canvas.style.width = W + "px";
canvas.style.height = H + "px";
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
horizon = H * 0.24;
}
addEventListener("resize", resize);
resize();
function roadWidth(z) {
return W * (0.045 + 0.39 * z);
}
function screenX(l, z) {
return W / 2 + l * roadWidth(z) * 0.62;
}
function screenY(z) {
return horizon + (H - horizon) * z;
}
function scale(z) {
return 0.15 + 1.2 * z;
}
function rand(a, b) {
return Math.random() * (b - a) + a;
}
function spawnObjects() {
let r = Math.random();
let type = r < 0.53 ? "train" : r < 0.78 ? "barrier" : "coin";
let l = Math.floor(Math.random() * 3) - 1;
objects.push({ type, l, z: 0, hit: false });
if (Math.random() < 0.36) {
let other = [-1, 0, 1].filter((x) => x !== l);
objects.push({
type: "coin",
l: other[Math.floor(Math.random() * other.length)],
z: -0.25,
hit: false,
});
}
}
function start() {
lane = 0;
jump = 0;
slide = 0;
vy = 0;
score = 0;
coins = 0;
speed = 0.38;
objects = [];
spawn = 0.2;
time = 0;
running = true;
over = false;
menu.style.display = "none";
}
document.getElementById("start").onclick = start;
function move(d) {
if (running) lane = Math.max(-1, Math.min(1, lane + d));
}
function doJump() {
if (running && jump === 0 && slide <= 0) {
vy = 1.05;
}
}
function doSlide() {
if (running && jump === 0) slide = 0.65;
}
addEventListener("keydown", (e) => {
if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", " "].includes(e.key))
e.preventDefault();
if (!running) {
if (e.key === "Enter" || e.key === " ") start();
return;
}
if (e.key === "ArrowLeft" || e.key.toLowerCase() === "a") move(-1);
if (e.key === "ArrowRight" || e.key.toLowerCase() === "d") move(1);
if (e.key === "ArrowUp" || e.key === " ") doJump();
if (e.key === "ArrowDown" || e.key.toLowerCase() === "s") doSlide();
});
document.getElementById("left").onclick = () => move(-1);
document.getElementById("right").onclick = () => move(1);
document.getElementById("jump").onclick = doJump;
document.getElementById("slide").onclick = doSlide;
let touchX = 0,
touchY = 0;
canvas.addEventListener(
"touchstart",
(e) => {
touchX = e.changedTouches[0].clientX;
touchY = e.changedTouches[0].clientY;
},
{ passive: true },
);
canvas.addEventListener(
"touchend",
(e) => {
let dx = e.changedTouches[0].clientX - touchX;
let dy = e.changedTouches[0].clientY - touchY;
if (Math.abs(dx) > 25 || Math.abs(dy) > 25) {
if (Math.abs(dx) > Math.abs(dy)) move(dx > 0 ? 1 : -1);
else if (dy < 0) doJump();
else doSlide();
}
},
{ passive: true },
);
function polygon(points, color) {
ctx.fillStyle = color;
ctx.beginPath();
points.forEach((p, i) => (i ? ctx.lineTo(p[0], p[1]) : ctx.moveTo(p[0], p[1])));
ctx.closePath();
ctx.fill();
}
function drawWorld(dt) {
let sky = ctx.createLinearGradient(0, 0, 0, H);
sky.addColorStop(0, "#071b45");
sky.addColorStop(0.55, "#20a9c5");
sky.addColorStop(1, "#f6b96b");
ctx.fillStyle = sky;
ctx.fillRect(0, 0, W, H);
// Sun and distant city
ctx.fillStyle = "#ffe7a0";
ctx.beginPath();
ctx.arc(W * 0.78, H * 0.14, Math.min(W, H) * 0.045, 0, Math.PI * 2);
ctx.fill();
for (let i = 0; i < 20; i++) {
let x = (i * W) / 18;
let bh = 20 + ((i * 37) % 65);
ctx.fillStyle = i % 2 ? "#173b59" : "#214d67";
ctx.fillRect(x, horizon - bh, W / 23, bh);
}
// Ground
ctx.fillStyle = "#197c4a";
ctx.fillRect(0, horizon, W, H - horizon);
let rw = roadWidth(1),
rt = roadWidth(0);
polygon(
[
[W / 2 - rt, horizon],
[W / 2 + rt, horizon],
[W / 2 + rw, H],
[W / 2 - rw, H],
],
"#404d5b",
);
polygon(
[
[W / 2 - rt * 0.88, horizon],
[W / 2 - rt * 0.83, horizon],
[W / 2 - rw * 0.94, H],
[W / 2 - rw * 0.88, H],
],
"#dbe9ec",
);
polygon(
[
[W / 2 + rt * 0.83, horizon],
[W / 2 + rt * 0.88, horizon],
[W / 2 + rw * 0.88, H],
[W / 2 + rw * 0.94, H],
],
"#dbe9ec",
);
// Three lanes and moving road markings
for (let l = -1; l <= 1; l++) {
let xTop = W / 2 + l * rt * 0.62,
xBot = W / 2 + l * rw * 0.62;
if (l !== -1) {
for (let i = 0; i < 10; i++) {
let z = (i / 10 + time * 0.65) % 1;
let y = screenY(z),
s = scale(z);
let x = W / 2 + (xTop - W / 2) * (1 - z) + (xBot - W / 2) * z;
ctx.fillStyle = "#b8c9d5";
ctx.fillRect(x - 1.5 * s, y, 3 * s, 12 * s);
}
}
}
}
function drawTrain(x, y, s) {
let w = 48 * s,
h = 100 * s;
ctx.fillStyle = "#162b3d";
ctx.fillRect(x - w / 2, y - h, w, h);
let g = ctx.createLinearGradient(x - w / 2, 0, x + w / 2, 0);
g.addColorStop(0, "#f7a32c");
g.addColorStop(0.45, "#fff1bc");
g.addColorStop(1, "#cf5227");
ctx.fillStyle = g;
ctx.fillRect(x - w / 2 + 3 * s, y - h + 4 * s, w - 6 * s, h - 8 * s);
ctx.fillStyle = "#152f4d";
ctx.fillRect(x - w / 2 + 6 * s, y - h + 12 * s, w - 12 * s, 25 * s);
ctx.fillStyle = "#8deaff";
ctx.fillRect(x - w / 2 + 9 * s, y - h + 15 * s, w - 18 * s, 18 * s);
ctx.fillStyle = "#ffed85";
ctx.fillRect(x - w / 2 + 5 * s, y - 10 * s, 8 * s, 5 * s);
ctx.fillRect(x + w / 2 - 13 * s, y - 10 * s, 8 * s, 5 * s);
ctx.fillStyle = "#1d2c3a";
ctx.fillRect(x - w / 2 - 3 * s, y - 2 * s, w + 6 * s, 5 * s);
}
function drawBarrier(x, y, s) {
let w = 48 * s,
h = 37 * s;
ctx.fillStyle = "#283746";
ctx.fillRect(x - w / 2, y - h, w, h);
ctx.fillStyle = "#ff5d36";
ctx.fillRect(x - w / 2, y - h, w, 10 * s);
ctx.fillStyle = "#ffe5bd";
ctx.fillRect(x - w / 2 + 5 * s, y - h + 14 * s, w - 10 * s, 5 * s);
ctx.fillStyle = "#d7e0e7";
ctx.fillRect(x - w / 2 + 5 * s, y - 4 * s, 6 * s, 10 * s);
ctx.fillRect(x + w / 2 - 11 * s, y - 4 * s, 6 * s, 10 * s);
}
function drawCoin(x, y, s) {
ctx.save();
ctx.translate(x, y - 23 * s);
ctx.fillStyle = "#ffae16";
ctx.beginPath();
ctx.ellipse(0, 0, 11 * s, 14 * s, 0, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = "#fff17a";
ctx.lineWidth = 3 * s;
ctx.stroke();
ctx.fillStyle = "#fff4a8";
ctx.font = `bold ${17 * s}px Arial`;
ctx.textAlign = "center";
ctx.fillText("$", 0, 6 * s);
ctx.restore();
}
function drawPlayer() {
let x = screenX(lane, 1),
base = H * 0.84 - jump * 90;
let s = Math.max(0.7, Math.min(1.2, H / 700));
ctx.save();
ctx.translate(x, base);
// Shadow
ctx.fillStyle = "#06132277";
ctx.beginPath();
ctx.ellipse(0, 8, 23 * s, 7 * s, 0, 0, Math.PI * 2);
ctx.fill();
if (slide > 0) {
ctx.rotate(-0.18);
ctx.fillStyle = "#27c9ed";
ctx.fillRect(-23 * s, -30 * s, 43 * s, 22 * s);
ctx.fillStyle = "#f1bd87";
ctx.beginPath();
ctx.arc(20 * s, -22 * s, 12 * s, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "#e9f6ff";
ctx.fillRect(-18 * s, -7 * s, 24 * s, 7 * s);
} else {
let swing = Math.sin(time * 22) * 7 * s;
ctx.strokeStyle = "#f1bd87";
ctx.lineWidth = 7 * s;
ctx.lineCap = "round";
ctx.beginPath();
ctx.moveTo(-8 * s, -38 * s);
ctx.lineTo(-15 * s + swing, -20 * s);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(8 * s, -38 * s);
ctx.lineTo(15 * s - swing, -22 * s);
ctx.stroke();
ctx.fillStyle = "#1761b8";
ctx.fillRect(-11 * s, -21 * s, 9 * s, 20 * s);
ctx.fillRect(2 * s, -21 * s, 9 * s, 20 * s);
ctx.fillStyle = "#f2f6ff";
ctx.fillRect(-13 * s, -2 * s, 13 * s, 5 * s);
ctx.fillRect(2 * s, -2 * s, 14 * s, 5 * s);
ctx.fillStyle = "#20c9ed";
ctx.beginPath();
ctx.roundRect(-14 * s, -55 * s, 28 * s, 34 * s, 7 * s);
ctx.fill();
ctx.fillStyle = "#f2bc88";
ctx.beginPath();
ctx.arc(0, -66 * s, 12 * s, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "#27374d";
ctx.beginPath();
ctx.arc(0, -70 * s, 12 * s, Math.PI, Math.PI * 2);
ctx.fill();
ctx.fillRect(-12 * s, -71 * s, 24 * s, 5 * s);
ctx.fillStyle = "#fff";
ctx.fillRect(-6 * s, -67 * s, 3 * s, 3 * s);
ctx.fillRect(4 * s, -67 * s, 3 * s, 3 * s);
}
ctx.restore();
}
function endGame() {
running = false;
over = true;
best = Math.max(best, Math.floor(score));
localStorage.setItem("metroBest", best);
document.getElementById("message").innerHTML =
`🏁 गेम ओवर!<br>स्कोर: ${Math.floor(score)}<br>🪙 सिक्के: ${coins}<br>🏆 बेस्ट: ${best}`;
document.getElementById("start").textContent = "↻ फिर से खेलें";
menu.style.display = "flex";
}
function update(dt) {
if (!running) return;
time += dt;
score += dt * 12;
speed = Math.min(0.72, 0.38 + score / 5000);
spawn -= dt;
if (spawn <= 0) {
spawnObjects();
spawn = rand(0.65, 1.1) / (speed / 0.38);
}
if (jump > 0 || vy > 0) {
jump += vy * dt;
vy -= 2.7 * dt;
if (jump < 0) {
jump = 0;
vy = 0;
}
}
if (slide > 0) slide = Math.max(0, slide - dt);
for (let o of objects) {
o.z += speed * dt;
if (o.hit) continue;
if (o.z > 0.86 && o.z < 1.04 && o.l === lane) {
if (o.type === "coin") {
o.hit = true;
coins++;
score += 30;
} else if (o.type === "train" && jump < 0.23) {
endGame();
return;
} else if (o.type === "barrier" && jump < 0.27 && slide < 0.1) {
endGame();
return;
}
}
}
objects = objects.filter((o) => o.z < 1.13 && !o.hit);
scoreEl.textContent = Math.floor(score);
coinsEl.textContent = coins;
}
function draw() {
drawWorld(0);
let sorted = [...objects].sort((a, b) => a.z - b.z);
for (let o of sorted) {
if (o.z < 0) continue;
let x = screenX(o.l, o.z),
y = screenY(o.z),
s = scale(o.z);
if (o.type === "train") drawTrain(x, y, s);
else if (o.type === "barrier") drawBarrier(x, y, s);
else drawCoin(x, y, s);
}
drawPlayer();
if (!running && !over) {
// Decorative preview
}
}
function loop(now) {
let dt = Math.min((now - last) / 1000 || 0, 0.04);
last = now;
update(dt);
draw();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body>
</html>