anycoder-b5d4e1c5 / index.html
Void2377's picture
Upload folder using huggingface_hub
53df2d9 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Neon Velocity: Cyber Racing</title>
<!-- Importing Google Fonts for Cyberpunk Aesthetic -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #00f3ff; /* Cyan */
--secondary: #ff0055; /* Magenta */
--accent: #ffee00; /* Yellow */
--bg-dark: #050510;
--glass: rgba(255, 255, 255, 0.05);
--border: rgba(255, 255, 255, 0.1);
--font-display: 'Orbitron', sans-serif;
--font-body: 'Rajdhani', sans-serif;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
user-select: none;
-webkit-user-select: none;
}
body {
background-color: var(--bg-dark);
color: white;
font-family: var(--font-body);
overflow: hidden;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
}
/* --- Header & Branding --- */
header {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 100;
pointer-events: none; /* Let clicks pass through to canvas if needed */
}
.brand {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 2px;
text-shadow: 0 0 10px var(--primary);
pointer-events: auto;
}
.brand span {
color: var(--secondary);
}
.built-with {
font-size: 0.8rem;
color: rgba(255,255,255,0.5);
text-decoration: none;
border: 1px solid var(--border);
padding: 5px 10px;
border-radius: 20px;
backdrop-filter: blur(5px);
transition: all 0.3s ease;
}
.built-with:hover {
background: var(--primary);
color: var(--bg-dark);
border-color: var(--primary);
box-shadow: 0 0 15px var(--primary);
}
/* --- Game Container --- */
#game-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: radial-gradient(circle at center, #1a1a2e 0%, #000000 100%);
}
canvas {
box-shadow: 0 0 50px rgba(0, 243, 255, 0.1);
max-width: 100%;
max-height: 100%;
}
/* --- UI Overlays --- */
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(8px);
z-index: 50;
transition: opacity 0.3s ease;
}
.overlay.hidden {
opacity: 0;
pointer-events: none;
}
h1 {
font-family: var(--font-display);
font-size: 4rem;
text-transform: uppercase;
background: linear-gradient(to right, var(--primary), var(--secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 1rem;
text-align: center;
filter: drop-shadow(0 0 20px rgba(0, 243, 255, 0.5));
animation: pulse 2s infinite;
}
.instructions {
margin-bottom: 2rem;
text-align: center;
color: #ccc;
font-size: 1.2rem;
line-height: 1.6;
}
.key-badge {
display: inline-block;
background: var(--glass);
border: 1px solid var(--primary);
padding: 5px 10px;
border-radius: 4px;
color: var(--primary);
font-weight: bold;
margin: 0 2px;
}
button.btn-primary {
background: transparent;
color: var(--primary);
font-family: var(--font-display);
font-size: 1.5rem;
padding: 1rem 3rem;
border: 2px solid var(--primary);
border-radius: 4px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 2px;
transition: all 0.2s ease;
box-shadow: 0 0 15px rgba(0, 243, 255, 0.2);
}
button.btn-primary:hover {
background: var(--primary);
color: var(--bg-dark);
box-shadow: 0 0 30px var(--primary);
transform: scale(1.05);
}
/* --- HUD (Heads Up Display) --- */
#hud {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 40;
display: none; /* Hidden until game starts */
}
.hud-panel {
background: rgba(0, 0, 0, 0.5);
border-left: 3px solid var(--secondary);
padding: 10px 20px;
backdrop-filter: blur(4px);
}
.hud-label {
font-size: 0.8rem;
color: var(--secondary);
text-transform: uppercase;
letter-spacing: 1px;
}
.hud-value {
font-family: var(--font-display);
font-size: 1.5rem;
color: white;
}
/* --- Mobile Controls --- */
#mobile-controls {
position: absolute;
bottom: 20px;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 60;
display: none; /* Shown via JS on touch devices */
}
.control-btn {
width: 80px;
height: 80px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 2px solid var(--primary);
color: white;
font-size: 2rem;
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(5px);
touch-action: manipulation;
}
.control-btn:active {
background: var(--primary);
color: black;
}
/* --- Animations --- */
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.02); opacity: 0.9; }
100% { transform: scale(1); opacity: 1; }
}
@media (max-width: 768px) {
h1 { font-size: 2.5rem; }
.instructions { font-size: 1rem; }
#hud { top: 10px; }
.hud-value { font-size: 1.2rem; }
}
</style>
</head>
<body>
<header>
<div class="brand">Neon <span>Racer</span></div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">Built with anycoder</a>
</header>
<main id="game-container">
<!-- Canvas Layer -->
<canvas id="gameCanvas"></canvas>
<!-- Heads Up Display -->
<div id="hud">
<div class="hud-panel">
<div class="hud-label">Score</div>
<div class="hud-value" id="scoreDisplay">0</div>
</div>
<div class="hud-panel" style="border-left: none; border-right: 3px solid var(--primary); text-align: right;">
<div class="hud-label">Speed</div>
<div class="hud-value" id="speedDisplay">0 km/h</div>
</div>
</div>
<!-- Start Screen -->
<div id="startScreen" class="overlay">
<h1>Neon Velocity</h1>
<div class="instructions">
<p>Use <span class="key-badge"></span> <span class="key-badge"></span> or <span class="key-badge">A</span> <span class="key-badge">D</span> to steer.</p>
<p>Avoid the red obstacles. Collect yellow energy.</p>
<p style="font-size: 0.8rem; margin-top: 10px; color: #888;">(Mobile: Tap left/right sides of screen)</p>
</div>
<button class="btn-primary" id="startBtn">Start Engine</button>
</div>
<!-- Game Over Screen -->
<div id="gameOverScreen" class="overlay hidden">
<h1 style="color: var(--secondary); -webkit-text-fill-color: var(--secondary);">CRASHED!</h1>
<div class="instructions">
<p>Final Score: <span id="finalScore" style="color: white; font-weight: bold;">0</span></p>
<p>High Score: <span id="highScore" style="color: var(--accent);">0</span></p>
</div>
<button class="btn-primary" id="restartBtn">Try Again</button>
</div>
<!-- Mobile Controls -->
<div id="mobile-controls">
<div class="control-btn" id="btnLeft"></div>
<div class="control-btn" id="btnRight"></div>
</div>
</main>
<script>
/**
* AUDIO SYSTEM (Web Audio API)
* Synthesizes sounds locally without external assets.
*/
const AudioSys = {
ctx: null,
init: function() {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
this.ctx = new AudioContext();
},
playTone: function(freq, type, duration, vol = 0.1) {
if (!this.ctx) return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = type;
osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
gain.gain.setValueAtTime(vol, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start();
osc.stop(this.ctx.currentTime + duration);
},
playCrash: function() {
this.playTone(100, 'sawtooth', 0.5, 0.3);
this.playTone(50, 'square', 0.5, 0.3);
},
playCollect: function() {
this.playTone(800, 'sine', 0.1, 0.1);
setTimeout(() => this.playTone(1200, 'sine', 0.2, 0.1), 50);
},
playEngine: function() {
// Simple hum for engine (simulated by random noise usually, but keeping it simple here)
}
};
/**
* GAME ENGINE & LOGIC
*/
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// UI Elements
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const hud = document.getElementById('hud');
const scoreDisplay = document.getElementById('scoreDisplay');
const speedDisplay = document.getElementById('speedDisplay');
const finalScoreDisplay = document.getElementById('finalScore');
const highScoreDisplay = document.getElementById('highScore');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const mobileControls = document.getElementById('mobile-controls');
const btnLeft = document.getElementById('btnLeft');
const btnRight = document.getElementById('btnRight');
// Game State
let gameRunning = false;
let score = 0;
let highScore = localStorage.getItem('neonRacerHighScore') || 0;
let speed = 5;
let roadOffset = 0;
let animationId;
let lastTime = 0;
// Dimensions
let canvasWidth, canvasHeight;
// Entities
const player = {
x: 0,
y: 0,
width: 40,
height: 70,
color: '#00f3ff',
speedX: 0,
maxSpeedX: 7,
tilt: 0
};
let obstacles = [];
let particles = [];
let roadLines = [];
// Inputs
const keys = {
ArrowLeft: false,
ArrowRight: false,
KeyA: false,
KeyD: false
};
// Resize Handling
function resize() {
canvasWidth = window.innerWidth;
canvasHeight = window.innerHeight;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// Reposition player on resize if game hasn't started
if (!gameRunning) {
player.x = canvasWidth / 2 - player.width / 2;
player.y = canvasHeight - 150;
}
}
window.addEventListener('resize', resize);
// Input Listeners
window.addEventListener('keydown', (e) => {
if (keys.hasOwnProperty(e.code)) keys[e.code] = true;
});
window.addEventListener('keyup', (e) => {
if (keys.hasOwnProperty(e.code)) keys[e.code] = false;
});
// Mobile Touch
const handleTouch = (dir) => (e) => {
e.preventDefault(); // Prevent scroll
if (dir === 'left') keys.ArrowLeft = true;
if (dir === 'right') keys.ArrowRight = true;
};
const handleTouchEnd = (dir) => (e) => {
e.preventDefault();
if (dir === 'left') keys.ArrowLeft = false;
if (dir === 'right') keys.ArrowRight = false;
};
if ('ontouchstart' in window) {
mobileControls.style.display = 'flex';
btnLeft.addEventListener('touchstart', handleTouch('left'));
btnLeft.addEventListener('touchend', handleTouchEnd('left'));
btnRight.addEventListener('touchstart', handleTouch('right'));
btnRight.addEventListener('touchend', handleTouchEnd('right'));
}
// Game Functions
function initGame() {
resize();
player.x = canvasWidth / 2 - player.width / 2;
player.y = canvasHeight - 150;
obstacles = [];
particles = [];
roadLines = [];
score = 0;
speed = 5;
gameRunning = true;
// Create initial road lines
for(let i=0; i<10; i++) {
roadLines.push({ y: i * 100 });
}
startScreen.classList.add('hidden');
gameOverScreen.classList.add('hidden');
hud.style.display = 'flex';
AudioSys.init();
lastTime = performance.now();
requestAnimationFrame(gameLoop);
}
function createObstacle() {
const laneWidth = canvasWidth / 4; // 4 lanes roughly
const lane = Math.floor(Math.random() * 4);
const obsWidth = 40;
const obsHeight = 70;
const obsX = (lane * laneWidth) + (laneWidth/2) - (obsWidth/2) + 20; // Center in lane with margin
// 20% chance for bonus coin
const isCoin = Math.random() > 0.8;
obstacles.push({
x: obsX,
y: -100,
width: obsWidth,
height: obsHeight,
color: isCoin ? '#ffee00' : '#ff0055',
type: isCoin ? 'coin' : 'obstacle',
rotation: 0
});
}
function createExplosion(x, y, color) {
for (let i = 0; i < 20; i++) {
particles.push({
x: x,
y: y,
vx: (Math.random() - 0.5) * 10,
vy: (Math.random() - 0.5) * 10,
life: 1.0,
color: color
});
}
}
function update(dt) {
// Player Movement
if (keys.ArrowLeft || keys.KeyA) {
player.x -= player.maxSpeedX;
player.tilt = -15; // degrees
} else if (keys.ArrowRight || keys.KeyD) {
player.x += player.maxSpeedX;
player.tilt = 15;
} else {
player.tilt = 0;
}
// Boundaries
if (player.x < 0) player.x = 0;
if (player.x + player.width > canvasWidth) player.x = canvasWidth - player.width;
// Road Animation
roadOffset += speed;
if (roadOffset >= 100) roadOffset = 0;
// Spawn Obstacles
if (Math.random() < 0.02) { // Adjust spawn rate based on speed
createObstacle();
}
// Update Obstacles
for (let i = obstacles.length - 1; i >= 0; i--) {
let obs = obstacles[i];
obs.y += speed;
obs.rotation += 0.05;
// Collision Detection (AABB)
if (
player.x < obs.x + obs.width &&
player.x + player.width > obs.x &&
player.y < obs.y + obs.height &&
player.y + player.height > obs.y
) {
if (obs.type === 'coin') {
// Collect Coin
score += 100;
createExplosion(obs.x + obs.width/2, obs.y + obs.height/2, '#ffee00');
AudioSys.playCollect();
obstacles.splice(i, 1);
} else {
// Crash
createExplosion(player.x + player.width/2, player.y + player.height/2, '#ff0055');
AudioSys.playCrash();
gameOver();
}
} else if (obs.y > canvasHeight) {
obstacles.splice(i, 1);
score += 10; // Points for passing
}
}
// Update Particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.life -= 0.02;
if (p.life <= 0) particles.splice(i, 1);
}
// Increase Difficulty
speed = 5 + (score / 500); // Cap speed at reasonable level
score++;
// Update UI
scoreDisplay.innerText = score;
speedDisplay.innerText = Math.floor(speed * 20) + " km/h";
}
function draw() {
// Clear Screen
ctx.fillStyle = '#050510';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// Draw Road (Perspective effect simplified to top-down for clarity)
ctx.fillStyle = '#111';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// Draw Road Borders
ctx.strokeStyle = '#00f3ff';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(canvasWidth * 0.1, 0);
ctx.lineTo(canvasWidth * 0.1, canvasHeight);
ctx.moveTo(canvasWidth * 0.9, 0);
ctx.lineTo(canvasWidth * 0.9, canvasHeight);
ctx.stroke();
// Draw Moving Lines
ctx.strokeStyle = 'rgba(0, 243, 255, 0.3)';
ctx.lineWidth = 2;
roadLines.forEach(line => {
line.y += speed;
if (line.y > canvasHeight) line.y = -100;
ctx.beginPath();
ctx.moveTo(canvasWidth * 0.3, line.y);
ctx.lineTo(canvasWidth * 0.3, line.y + 50);
ctx.moveTo(canvasWidth * 0.7, line.y);
ctx.lineTo(canvasWidth * 0.7, line.y + 50);
ctx.stroke();
});
// Draw Player Car
ctx.save();
ctx.translate(player.x + player.width / 2, player.y + player.height / 2);
ctx.rotate(player.tilt * Math.PI / 180);
// Car Body
ctx.shadowBlur = 15;
ctx.shadowColor = player.color;
ctx.fillStyle = player.color;
ctx.fillRect(-player.width/2, -player.height/2, player.width, player.height);
// Car Detail (Windshield)
ctx.fillStyle = '#000';
ctx.fillRect(-player.width/2 + 5, -player.height/2 + 10, player.width - 10, 15);
// Engine Glow
ctx.fillStyle = '#ff0055';
ctx.fillRect(-player.width/2 + 5, player.height/2 - 5, player.width - 10, 5);
ctx.restore();
// Draw Obstacles
obstacles.forEach(obs => {
ctx.save();
ctx.translate(obs.x + obs.width/2, obs.y + obs.height/2);
ctx.rotate(obs.rotation);
ctx.shadowBlur = 10;
ctx.shadowColor = obs.color;
ctx.fillStyle = obs.color;
// Draw shape based on type
if (obs.type === 'coin') {
ctx.beginPath();
ctx.arc(0, 0, obs.width/2, 0, Math.PI * 2);
ctx.fill();
// Shine
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(-5, -5, 5, 0, Math.PI * 2);
ctx.fill();
} else {
ctx.fillRect(-obs.width/2, -obs.height/2, obs.width, obs.height);
// Inner detail
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(-obs.width/2 + 5, -obs.height/2 + 5, obs.width - 10, obs.height - 10);
}
ctx.restore();
});
// Draw Particles
particles.forEach(p => {
ctx.globalAlpha = p.life;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1.0;
});
}
function gameLoop(timestamp) {
if (!gameRunning) return;
const dt = timestamp - lastTime;
lastTime = timestamp;
update(dt);
draw();
animationId = requestAnimationFrame(gameLoop);
}
function gameOver() {
gameRunning = false;
cancelAnimationFrame(animationId);
// Update High Score
if (score > highScore) {
highScore = score;
localStorage.setItem('neonRacerHighScore', highScore);
}
finalScoreDisplay.innerText = score;
highScoreDisplay.innerText = highScore;
hud.style.display = 'none';
gameOverScreen.classList.remove('hidden');
}
// Button Listeners
startBtn.addEventListener('click', initGame);
restartBtn.addEventListener('click', initGame);
// Initial Draw to show something before start
resize();
// Draw a static frame
ctx.fillStyle = '#050510';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.fillStyle = '#00f3ff';
ctx.font = '20px Orbitron';
ctx.textAlign = 'center';
ctx.fillText("READY TO RACE?", canvasWidth/2, canvasHeight/2);
</script>
</body>
</html>