Track Legends
by CosmicMaker16811 lines13.2 KB
<!DOCTYPE html>
<html>
<head>
<title>Track Legends</title>
<style>
body {
margin: 0;
background: #07111f;
color: white;
font-family: Arial, sans-serif;
text-align: center;
}
h1 {
font-size: 40px;
}
#game {
max-width: 1000px;
margin: auto;
padding: 20px;
}
#stats {
display: flex;
justify-content: center;
gap: 15px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stat {
background: #12243b;
padding: 12px 18px;
border-radius: 10px;
}
#track {
position: relative;
height: 300px;
background: linear-gradient(
#68b5ed 0%,
#68b5ed 35%,
#65a94e 35%,
#65a94e 50%,
#b8493c 50%,
#b8493c 100%
);
border-radius: 15px;
overflow: hidden;
}
.lane {
position: absolute;
left: 0;
width: 100%;
border-top: 3px solid white;
}
.lane1 { top: 100px; }
.lane2 { top: 150px; }
.lane3 { top: 200px; }
#finish {
position: absolute;
right: 35px;
top: 70px;
height: 180px;
width: 10px;
background: repeating-linear-gradient(
to bottom,
white 0px,
white 15px,
black 15px,
black 30px
);
}
#runner {
position: absolute;
left: 25px;
top: 110px;
font-size: 45px;
transform: scaleX(-1);
}
#bar {
width: 100%;
height: 20px;
background: #172b44;
margin-top: 15px;
border-radius: 20px;
overflow: hidden;
}
#progress {
height: 100%;
width: 0%;
background: #35e57d;
}
button {
background: #278cff;
color: white;
border: none;
padding: 12px 20px;
border-radius: 10px;
margin: 5px;
cursor: pointer;
font-weight: bold;
}
button:hover {
filter: brightness(1.15);
}
button:disabled {
opacity: .4;
cursor: not-allowed;
}
.upgrade-container {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 15px;
}
.upgrade {
background: #12243b;
padding: 18px;
border-radius: 12px;
width: 220px;
}
#message {
font-size: 20px;
min-height: 30px;
margin: 15px;
}
#controls {
font-size: 18px;
margin: 10px;
}
</style>
</head>
<body>
<div id="game">
<h1>🏃 TRACK LEGENDS</h1>
<div id="stats">
<div class="stat">💰 $<span id="money">100</span></div>
<div class="stat">⚡ Speed <span id="speed">1.00</span>x</div>
<div class="stat">🏆 Wins <span id="wins">0</span></div>
<div class="stat">🌎 <span id="rank">Local</span></div>
</div>
<div id="controls">
<b>ALTERNATE ← LEFT AND RIGHT → AS FAST AS YOU CAN!</b>
</div>
<div id="track">
<div class="lane lane1"></div>
<div class="lane lane2"></div>
<div class="lane lane3"></div>
<div id="finish"></div>
<div id="runner">🏃</div>
</div>
<div id="bar">
<div id="progress"></div>
</div>
<div id="message">
Press START RACE!
</div>
<button id="startButton" onclick="startRace()">
START RACE
</button>
<button onclick="resetRace()">
RESET
</button>
<div class="card">
<h2>⚙️ UPGRADES</h2>
<div class="upgrade-container">
<div class="upgrade">
<h3>👟 Sprint Shoes</h3>
<p>Increase your running power.</p>
<button id="shoeButton" onclick="buyShoes()">
Buy $<span id="shoeCost">75</span>
</button>
<p>Level: <span id="shoeLevel">0</span></p>
</div>
<div class="upgrade">
<h3>💪 Training</h3>
<p>Increase your base speed.</p>
<button id="trainingButton" onclick="buyTraining()">
Buy $<span id="trainingCost">100</span>
</button>
<p>Level: <span id="trainingLevel">0</span></p>
</div>
<div class="upgrade">
<h3>🔥 Adrenaline</h3>
<p>Make every alternating press stronger.</p>
<button id="adrenalineButton" onclick="buyAdrenaline()">
Buy $<span id="adrenalineCost">150</span>
</button>
<p>Level: <span id="adrenalineLevel">0</span></p>
</div>
</div>
</div>
<div class="card">
<h2>🏟️ CAREER</h2>
<p>
Local Meets →
<span id="local">🔒</span>
</p>
<p>
Regional Finals →
<span id="regional">🔒</span>
</p>
<p>
Elite Championships →
<span id="elite">🔒</span>
</p>
<p>
Olympic Games →
<span id="olympic">🔒</span>
</p>
<button id="olympicButton"
onclick="startOlympics()"
disabled>
🏅 OLYMPICS LOCKED
</button>
</div>
</div>
<script>
/* =========================
GAME VARIABLES
========================= */
let money = 100;
let wins = 0;
let running = false;
let distance = 0;
let runPower = 0;
let lastKey = "";
let raceStartTime = 0;
let raceType = "normal";
/* UPGRADES */
let shoeLevel = 0;
let trainingLevel = 0;
let adrenalineLevel = 0;
/* =========================
ELEMENTS
========================= */
const runner = document.getElementById("runner");
const progressBar =
document.getElementById("progress");
const message =
document.getElementById("message");
const startButton =
document.getElementById("startButton");
/* =========================
SPEED
========================= */
function getSpeed() {
return (
1
+ trainingLevel * 0.15
+ shoeLevel * 0.10
+ adrenalineLevel * 0.08
);
}
/* =========================
START RACE
========================= */
function startRace() {
if (running) return;
running = true;
distance = 0;
runPower = 0;
lastKey = "";
raceStartTime = performance.now();
startButton.disabled = true;
message.innerHTML =
"🔥 GO! Alternate LEFT and RIGHT!";
gameLoop();
}
/* =========================
GAME LOOP
========================= */
function gameLoop() {
if (!running) return;
/*
IMPORTANT:
The runner DOES NOT move automatically.
runPower only increases when
the player correctly alternates
left and right.
*/
if (runPower > 0) {
let movement =
runPower * getSpeed();
distance += movement;
/*
Slowly lose speed if the player
stops pressing keys.
*/
runPower *= 0.94;
}
/*
Convert distance to percentage.
*/
let percent =
Math.min(distance, 100);
progressBar.style.width =
percent + "%";
/*
Move runner.
Track width is 1000-ish, so
we calculate position based on %.
*/
let trackWidth =
document.getElementById("track").clientWidth;
let maxPosition =
trackWidth - 100;
let position =
25 + (percent / 100) * maxPosition;
runner.style.left =
position + "px";
/*
Finish
*/
if (distance >= 100) {
finishRace();
return;
}
requestAnimationFrame(gameLoop);
}
/* =========================
ARROW KEYS
========================= */
document.addEventListener("keydown", function(event) {
if (!running) return;
if (
event.key !== "ArrowLeft" &&
event.key !== "ArrowRight"
) {
return;
}
event.preventDefault();
/*
Only alternating arrows
increase speed.
LEFT → RIGHT → LEFT → RIGHT
*/
if (event.key !== lastKey) {
runPower +=
0.75 + adrenalineLevel * 0.12;
lastKey = event.key;
/*
Small visual bounce
*/
runner.style.transform =
"scaleX(-1) translateY(-5px)";
setTimeout(() => {
runner.style.transform =
"scaleX(-1) translateY(0)";
}, 60);
}
});
/* =========================
FINISH
========================= */
function finishRace() {
running = false;
let finishTime =
(performance.now() - raceStartTime) / 1000;
wins++;
let reward =
50 + Math.floor(
Math.max(0, 100 - finishTime * 8)
);
/*
Olympics gives bigger rewards.
*/
if (raceType === "olympic") {
reward *= 5;
}
money += reward;
startButton.disabled = false;
message.innerHTML =
"🏁 FINISH! " +
finishTime.toFixed(2) +
" seconds — 💰 +$" +
reward;
updateGame();
}
/* =========================
RESET
========================= */
function resetRace() {
running = false;
distance = 0;
runPower = 0;
lastKey = "";
progressBar.style.width = "0%";
runner.style.left = "25px";
startButton.disabled = false;
message.innerHTML =
"Press START RACE!";
}
/* =========================
SHOES
========================= */
function shoeCost() {
return Math.floor(
75 * Math.pow(1.6, shoeLevel)
);
}
function buyShoes() {
let cost = shoeCost();
if (money < cost) return;
money -= cost;
shoeLevel++;
updateGame();
}
/* =========================
TRAINING
========================= */
function trainingCost() {
return Math.floor(
100 * Math.pow(1.6, trainingLevel)
);
}
function buyTraining() {
let cost = trainingCost();
if (money < cost) return;
money -= cost;
trainingLevel++;
updateGame();
}
/* =========================
ADRENALINE
========================= */
function adrenalineCost() {
return Math.floor(
150 * Math.pow(1.6, adrenalineLevel)
);
}
function buyAdrenaline() {
let cost = adrenalineCost();
if (money < cost) return;
money -= cost;
adrenalineLevel++;
updateGame();
}
/* =========================
OLYMPICS
========================= */
function startOlympics() {
if (wins < 5) return;
raceType = "olympic";
resetRace();
message.innerHTML =
"🏅 OLYMPIC FINAL! GET READY!";
}
/* =========================
UPDATE UI
========================= */
function updateGame() {
document.getElementById("money")
.textContent = Math.floor(money);
document.getElementById("wins")
.textContent = wins;
document.getElementById("speed")
.textContent =
getSpeed().toFixed(2);
document.getElementById("shoeLevel")
.textContent = shoeLevel;
document.getElementById("trainingLevel")
.textContent = trainingLevel;
document.getElementById("adrenalineLevel")
.textContent = adrenalineLevel;
document.getElementById("shoeCost")
.textContent = shoeCost();
document.getElementById("trainingCost")
.textContent = trainingCost();
document.getElementById("adrenalineCost")
.textContent = adrenalineCost();
/*
RANK
*/
let rank = "Local";
if (wins >= 10)
rank = "Elite";
else if (wins >= 5)
rank = "Regional";
else if (wins >= 2)
rank = "Rookie";
if (wins >= 15)
rank = "Olympian";
document.getElementById("rank")
.textContent = rank;
/*
CAREER
*/
document.getElementById("local")
.textContent =
wins >= 1 ? "✅" : "🔒";
document.getElementById("regional")
.textContent =
wins >= 2 ? "✅" : "🔒";
document.getElementById("elite")
.textContent =
wins >= 10 ? "✅" : "🔒";
document.getElementById("olympic")
.textContent =
wins >= 5 ? "🏅 UNLOCKED" : "🔒";
/*
OLYMPIC BUTTON
*/
let olympicButton =
document.getElementById("olympicButton");
if (wins >= 5) {
olympicButton.disabled = false;
olympicButton.innerHTML =
"🏅 ENTER OLYMPICS";
} else {
olympicButton.disabled = true;
olympicButton.innerHTML =
"🏅 WIN " +
(5 - wins) +
" MORE RACES";
}
}
/* START */
updateGame();
</script>
</body>
</html>Game Source: Track Legends
Creator: CosmicMaker16
Libraries: none
Complexity: complex (811 lines, 13.2 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: track-legends-cosmicmaker16" to link back to the original. Then publish at arcadelab.ai/publish.