Try this!
Posted by Sing Along Hatter on 20/5/2026, 20:23:07
Copy this Code into an html compiler or save it as a .html file and run it! <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Luton Trail: VGA Edition</title> <style> /* FULL COLOR 90s VGA PALETTE */ :root { --bg-color: #2e1e0a; --panel-color: #e8dcc3; --text-main: #1a1005; --text-highlight: #ff6600; --text-bad: #cc0000; --luton-navy: #002D62; } body { background-color: var(--bg-color); color: var(--text-main); font-family: 'Georgia', 'Times New Roman', Times, serif; margin: 0; padding: 15px; display: flex; justify-content: center; user-select: none; } #game-container { width: 1000px; background-color: var(--panel-color); border: 8px solid #4a3118; border-radius: 4px; box-shadow: 0 10px 25px rgba(0,0,0,0.7); box-sizing: border-box; } /* HEADER */ header { background-color: var(--luton-navy); color: #fff; padding: 12px; border-bottom: 4px solid #4a3118; text-align: center; } h1 { margin: 0; text-transform: uppercase; letter-spacing: 3px; font-size: 28px; text-shadow: 2px 2px 0px rgba(0,0,0,0.5); } h1 span { color: var(--text-highlight); } /* SCREENS management via basic display toggle */ .screen { display: none; } .screen.active { display: block; } /* INTRO SCREEN */ #screen-intro { text-align: center; background: linear-gradient(to bottom, #d9c7a0, #c0ab80); border: 4px solid #8e6e46; margin: 30px; padding: 35px; } #intro-text p { font-size: 18px; line-height: 1.6; margin-bottom: 20px; color: #2b1d0e; } /* MAIN SATELLITE LAYOUT */ #main-layout-wrapper { width: 100%; } .game-split { display: flex; flex-direction: row; width: 100%; } /* HUD PANEL (Left) */ .hud { width: 300px; background-color: #d9c7a0; border-right: 4px solid #4a3118; padding: 15px; display: flex; flex-direction: column; gap: 10px; font-size: 15px; font-weight: bold; box-sizing: border-box; } .hud-group { border: 2px solid #8e6e46; background: rgba(255,255,255,0.3); padding: 8px; border-radius: 4px; } .hud-group-title { color: var(--luton-navy); text-transform: uppercase; font-size: 12px; letter-spacing: 1px; margin-bottom: 5px; border-bottom: 1px solid #8e6e46; } .hud-stat { display: flex; justify-content: space-between; margin-bottom: 4px;} .stat-val { color: #5c3c1e; } .stat-val.bad { color: var(--text-bad); } /* PLAYING INTERFACE (Right) */ #action-area { flex-grow: 1; padding: 15px; background-color: #f2e9d9; box-sizing: border-box; display: flex; flex-direction: column; } #canvas-container { border: 4px solid #8e6e46; background-color: #000; margin-bottom: 12px; line-height: 0; } canvas { image-rendering: pixelated; display: block; width: 100%; height: auto; } /* TICKER SYSTEM */ #ticker-container { height: 110px; border: 2px solid #8e6e46; background-color: #fff9ed; padding: 10px; font-size: 16px; overflow-y: auto; color: #333; line-height: 1.4; margin-bottom: 12px; box-sizing: border-box; } #ticker-container p { margin: 3px 0; } .alert-orange { color: #fff; background-color: var(--text-highlight); padding: 0 4px; font-weight: bold; } .alert-blue { color: #fff; background-color: var(--luton-navy); padding: 0 4px; font-weight: bold; } /* CONTROLS GATEWAY */ .controls { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; } button { background: linear-gradient(to bottom, #f3e9d9, #c7ac86); color: var(--text-main); border: 3px solid #4a3118; border-radius: 2px; padding: 10px; font-family: 'Georgia', serif; font-size: 14px; font-weight: bold; cursor: pointer; box-shadow: 2px 2px 0px rgba(0,0,0,0.3); } button:hover:not(:disabled) { background: linear-gradient(to bottom, #fff, #d9c7a0); } button:disabled { color: #888; border-color: #888; background: #ccc; cursor: not-allowed; box-shadow: none; } button.main-btn { background: linear-gradient(to bottom, #ff9933, #e65c00); color: #fff; border-color: #803300; font-size: 16px; text-transform: uppercase; } /* SCREEN END SETTINGS */ #screen-end { text-align: center; background-color: #2b1d0e; color: #d9c7a0; margin: 40px; padding: 40px; border: 6px solid var(--text-highlight); } </style> </head> <body> <div id="game-container"> <header> <h1><span>THE</span> LUTON <span>TRAIL</span></h1> </header> <div id="screen-intro" class="screen active"> <div id="intro-text"> <p style="font-weight:bold; color: var(--text-bad); font-size: 23px; margin-top:0;">A Brutal Reality — May 2009</p> <p>The Football Association has struck a devastating blow. Mismanagement by previous regimes resulted in financial collapse and an unprecedented total deduction of 30 points. It was too much to overcome.</p> <p>For the first time in history, Luton Town has dropped out of the Football League and into the Conference Premier.</p> <p>Yet, the spirit of the Town is unbroken. Just weeks ago, 40,000 Hatters descended on Wembley to watch Claude Gnakpa’s dramatic extra-time chip secure the Johnstone's Paint Trophy (3-2 vs Scunthorpe).</p> <p>You are Gary Sweet, CEO of the 2020 Consortium. Your task is grueling: manage weekly finances, hire staff, rebuild a squad limited to 25 players, expand a landlocked Kenilworth Road, and scale the pyramid to the Premier League.</p> <p>The trail back to the top starts now. The Conference awaits.</p> </div> <button onclick="startGame()" style="font-size: 18px; padding: 12px 30px;">Begin the Journey</button> </div> <div id="main-layout-wrapper" class="screen"> <div class="game-split"> <div class="hud"> <div class="hud-group"> <div class="hud-group-title">Status</div> <div class="hud-stat"><span>Year:</span> <span id="ui-year" class="stat-val">2009</span></div> <div class="hud-stat"><span>League:</span> <span id="ui-league" class="stat-val">CONFERENCE</span></div> <div class="hud-stat"><span>Week:</span> <span class="stat-val"><span id="ui-week">1</span>/46</span></div> <div class="hud-stat"><span>Points:</span> <span id="ui-points" class="stat-val">0</span></div> </div> <div class="hud-group"> <div class="hud-group-title">Finances</div> <div class="hud-stat"><span>Funds:</span> <span class="stat-val">£<span id="ui-funds">300</span>k</span></div> <div class="hud-stat"><span>Wages:</span> <span class="stat-val">£<span id="ui-wages">10</span>k/w</span></div> <div class="hud-stat"><span>Stadium Cap:</span> <span id="ui-capacity" class="stat-val">8000</span></div> </div> <div class="hud-group"> <div class="hud-group-title">Squad (Max 25)</div> <div class="hud-stat"><span>Players:</span> <span id="ui-squadSize" class="stat-val">16</span></div> <div class="hud-stat"><span>Tac. Quality:</span> <span id="ui-quality" class="stat-val">40</span></div> <div class="hud-stat"><span>Fitness:</span> <span class="stat-val"><span id="ui-fitness">100</span>%</span></div> </div> <div class="hud-group"> <div class="hud-group-title">Staff</div> <div class="hud-stat"><span>Physios:</span> <span id="ui-physios" class="stat-val">0</span></div> <div class="hud-stat"><span>Coaches:</span> <span id="ui-coaches" class="stat-val">0</span></div> </div> <div style="font-size:11px; color:#5c3c1e; text-align:center; margin-top:auto; padding-top:10px;">The Trail is Long. Pace Yourself.</div> </div> <div id="action-area"> <div id="canvas-container"> <canvas id="gameCanvas" width="640" height="280"></canvas> </div> <div id="ticker-container"> <div id="ticker"></div> </div> <div class="controls"> <button onclick="playMatchweek()" class="main-btn">Play Match</button> <button id="btn-player" onclick="signPlayer()">Sign Player</button> <button id="btn-physio" onclick="hireStaff('physio')">Hire Physio (£30k)</button> <button id="btn-coach" onclick="hireStaff('coach')">Hire Coach (£30k)</button> <button id="btn-stadium" onclick="upgradeStadium()">Expand Kenilworth (£250k)</button> <button id="btn-release" onclick="releasePlayer()" style="color:var(--text-bad);">Release Player</button> </div> </div> </div> <div id="screen-end" class="screen"> <div id="end-text" style="font-size: 24px; text-align: center; margin-top: 40px; line-height: 1.5;"></div> <br><br> <button onclick="location.reload()" _:block; margin: 0 auto; font-size:18px; padding:10px 20px;">Return to 2009</button> </div> </div> <script> // System State Setup const state = { year: 2009, leagueLvl: 0, week: 1, points: 0, funds: 300, fitness: 100, squadSize: 16, squadMax: 25, quality: 40, wages: 10, capacity: 8000, maxCapacity: 10356, physios: 0, coaches: 0, gameOver: false, isAnimating: false }; const leagues = [ { name: "CONFERENCE", target: 85, ticketVal: 10, minQuality: 40, tvMoney: 50 }, { name: "LEAGUE 2", target: 80, ticketVal: 15, minQuality: 60, tvMoney: 400 }, { name: "LEAGUE 1", target: 85, ticketVal: 18, minQuality: 80, tvMoney: 800 }, { name: "CHAMPIONSHIP", target: 75, ticketVal: 25, minQuality: 120, tvMoney: 5000 }, { name: "PREMIER LEAGUE", target: 40, ticketVal: 40, minQuality: 200, tvMoney: 100000 } ]; const playersDB = [ { era: 0, names: ["Claude Gnakpa", "Alex Lawless", "Andre Gray", "Paul Benson", "Mark Tyler", "Janos Kovacs"] }, { era: 1, names: ["Pelly Ruddock Mpanzu", "Cameron McGeehan", "Jack Marriott", "Danny Hylton", "Luke Guttridge", "Glen Rea"] }, { era: 2, names: ["James Justin", "James Collins", "Harry Cornick", "Alan Sheehan", "Matty Pearson", "Elliot Lee"] }, { era: 3, names: ["Sonny Bradley", "Elijah Adebayo", "Carlton Morris", "Tom Lockyer", "Amari'i Bell", "Kal Naismith"] }, { era: 4, names: ["Alfie Doughty", "Ross Barkley", "Tahith Chong", "Chiedozie Ogbene", "Albert Sambi Lokonga"] } ]; const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Robust Screen Router function changeActiveScreen(hideId, showId) { document.getElementById(hideId).style.display = 'none'; document.getElementById(showId).style.display = 'block'; } function startGame() { changeActiveScreen('screen-intro', 'main-layout-wrapper'); ticker("Arrived in the Conference Premier. It's a long road back.", "orange"); ticker("Sign historic stars when available, but mind your squad limit."); updateUI(); drawScene('ready'); } function updateUI() { const lData = leagues[state.leagueLvl]; document.getElementById('ui-year').innerText = state.year; document.getElementById('ui-league').innerText = lData.name; document.getElementById('ui-week').innerText = state.week; document.getElementById('ui-points').innerText = state.points; const fundsSpan = document.getElementById('ui-funds'); fundsSpan.innerText = Math.floor(state.funds); fundsSpan.className = (state.funds < 0) ? 'stat-val bad' : 'stat-val'; document.getElementById('ui-wages').innerText = state.wages; document.getElementById('ui-capacity').innerText = state.capacity; document.getElementById('ui-squadSize').innerText = state.squadSize; document.getElementById('ui-quality').innerText = state.quality; const fitnessSpan = document.getElementById('ui-fitness'); fitnessSpan.innerText = Math.floor(state.fitness); fitnessSpan.className = (state.fitness < 25) ? 'stat-val bad' : 'stat-val'; document.getElementById('ui-physios').innerText = state.physios; document.getElementById('ui-coaches').innerText = state.coaches; let playerCost = 50 + (state.leagueLvl * 100); document.getElementById('btn-player').innerText = `Sign Player (£${playerCost}k)`; document.getElementById('btn-player').disabled = (state.squadSize >= state.squadMax); if (state.leagueLvl === 4) { document.getElementById('btn-stadium').innerText = "Rebuild Bobbers (£5000k)"; document.getElementById('btn-stadium').disabled = (state.capacity >= 12200); } else { document.getElementById('btn-stadium').innerText = "Expand Kenilworth (£250k)"; document.getElementById('btn-stadium').disabled = (state.capacity >= state.maxCapacity); } } function ticker(msg, alertType = null) { const tickerDiv = document.getElementById('ticker'); const p = document.createElement('p'); let prefix = `Wk${state.week}: `; if(alertType === "orange") prefix += `<span class="alert-orange">ALERT</span> `; if(alertType === "blue") prefix += `<span class="alert-blue">INFO</span> `; p.innerHTML = prefix + msg; tickerDiv.appendChild(p); tickerDiv.parentElement.scrollTop = tickerDiv.parentElement.scrollHeight; } // VGA Visual Matrix Rendering function drawSkyAndGrass() { ctx.fillStyle = "#aadbff"; ctx.fillRect(0, 0, 640, 140); ctx.fillStyle = "#38761d"; ctx.fillRect(0, 140, 640, 140); for(let i=0; i<40; i++) { ctx.fillStyle = "#275214"; ctx.fillRect(Math.random()*640, 140 + Math.random()*140, 3, 3); } } function drawStadiumIllustrated() { ctx.fillStyle = "#001a39"; ctx.beginPath(); ctx.moveTo(50, 140); ctx.lineTo(100, 70); ctx.lineTo(540, 70); ctx.lineTo(590, 140); ctx.closePath(); ctx.fill(); ctx.fillStyle = "#8e6e46"; ctx.fillRect(50, 140, 540, 60); ctx.fillStyle = "#4a3118"; ctx.fillRect(10, 120, 620, 20); ctx.fillStyle = "#fff9ed"; for(let x=70; x<550; x+=45) { ctx.fillRect(x, 155, 15, 10); ctx.fillRect(x, 175, 15, 10); } ctx.fillStyle = "#fff"; ctx.font = "bold 14px Georgia, serif"; ctx.textAlign = "center"; ctx.fillText("KENILWORTH ROAD", 320, 133); } function drawPitchLines() { ctx.strokeStyle = "rgba(255,255,255,0.6)"; ctx.lineWidth = 2; ctx.strokeRect(20, 200, 600, 70); ctx.beginPath(); ctx.moveTo(320, 200); ctx.lineTo(320, 270); ctx.stroke(); ctx.beginPath(); ctx.arc(320, 235, 15, 0, Math.PI * 2); ctx.stroke(); } function drawScene(type) { drawSkyAndGrass(); drawStadiumIllustrated(); drawPitchLines(); if(type === 'ready') { ctx.fillStyle = "rgba(0,0,0,0.5)"; ctx.fillRect(180, 20, 280, 40); ctx.fillStyle = "#fff"; ctx.font = "18px Georgia, serif"; ctx.textAlign = "center"; ctx.fillText("READY FOR MATCHWEEK", 320, 45); } } function animateMatchAction(callback) { state.isAnimating = true; setButtonsDisabled(true); let players = []; for(let i=0; i<6; i++) { players.push({ x: 120 + Math.random()*400, y: 205 + Math.random()*45, color: (i < 3) ? "#ff6600" : "#ffffff" }); } let ball = { x: 320, y: 235, vx: (Math.random()>0.5?5:-5), vy: (Math.random()*2-1) }; let frame = 0; function renderAnimationFrame() { if (frame > 40) { state.isAnimating = false; setButtonsDisabled(false); updateUI(); callback(); return; } drawSkyAndGrass(); drawStadiumIllustrated(); drawPitchLines(); ball.x += ball.vx; ball.y += ball.vy; if(ball.y < 205 || ball.y > 265) ball.vy *= -1; if(ball.x < 25 || ball.x > 615) ball.vx *= -1; ctx.fillStyle = "#fff"; ctx.fillRect(ball.x, ball.y, 6, 6); players.forEach(p => { p.x += (Math.random()*6-3); p.y += (Math.random()*4-2); ctx.fillStyle = p.color; ctx.fillRect(p.x, p.y, 10, 12); }); frame++; requestAnimationFrame(renderAnimationFrame); } renderAnimationFrame(); } function drawMatchResult(resText, ptsText) { ctx.fillStyle = "rgba(0,0,0,0.75)"; ctx.fillRect(200, 25, 240, 60); ctx.strokeStyle = "#ff6600"; ctx.strokeRect(200, 25, 240, 60); ctx.font = "bold 24px Georgia, serif"; ctx.fillStyle = (resText === "WIN") ? "#44ff44" : ((resText === "DRAW") ? "#ffffff" : "#ff4444"); ctx.textAlign = "center"; ctx.fillText(resText, 320, 52); ctx.font = "14px Georgia, serif"; ctx.fillStyle = "#ddd"; ctx.fillText(ptsText, 320, 74); } function setButtonsDisabled(disabled) { document.querySelectorAll('.controls button').forEach(b => b.disabled = disabled); } function hireStaff(type) { if (state.funds >= 30) { state.funds -= 30; state.wages += 2; if(type === 'physio') { state.physios++; ticker("Hired a Backroom Physio. Recovery speeds augmented.", "blue"); } else { state.coaches++; state.quality += 2; ticker("Hired an Assistant Coach. Collective Technical stats improved.", "blue"); } updateUI(); } else { ticker("Insufficient liquid capital to employ extra staff members.", "orange"); } } function signPlayer() { if (state.squadSize >= state.squadMax) return; let cost = 50 + (state.leagueLvl * 100); if (state.funds >= cost) { state.funds -= cost; state.squadSize++; state.wages += 3 + (state.leagueLvl * 5); state.quality += 6; let era = Math.min(state.leagueLvl, 4); let pool = playersDB[era].names; let pName = pool[Math.floor(Math.random() * pool.length)]; ticker(`Completed contract signings for <strong>${pName}</strong>. Squad Quality boosted.`, "blue"); updateUI(); } else { ticker(`Acquisition failed. £${cost}k needed to buy players at this standard.`, "orange"); } } function releasePlayer() { if (state.squadSize <= 14) { ticker("Squad size is too small to release anybody safely."); return; } state.squadSize--; let wageSaved = 3 + (state.leagueLvl * 5); state.wages = Math.max(8, state.wages - wageSaved); state.quality = Math.max(20, state.quality - 5); ticker("Mutual termination processed. Wage burden minimized."); updateUI(); } function upgradeStadium() { if (state.leagueLvl === 4 && state.capacity < 12200) { if(state.funds >= 5000) { state.funds -= 5000; state.capacity = 12200; ticker("Bobbers Stand rebuilt completely for the top tier!", "orange"); updateUI(); } else { ticker("Bobbers stand overhaul demands £5,000k total cost.", "orange"); } return; } if (state.funds >= 250) { state.funds -= 250; state.capacity = Math.min(state.maxCapacity, state.capacity + 500); ticker(`Safety works completed. Capacity safely grown to ${state.capacity}.`, "blue"); updateUI(); } else { ticker("Renovation projects call for a minimum of £250k.", "orange"); } } function playMatchweek() { if (state.gameOver || state.isAnimating) return; const lData = leagues[state.leagueLvl]; animateMatchAction(() => { state.funds -= state.wages; let capacityFactor = Math.max(0.5, (state.fitness / 100)); let attendance = Math.floor(state.capacity * 0.85 * capacityFactor); let gateIncome = (attendance * lData.ticketVal) / 1000; state.funds += gateIncome; let drain = 6 - (state.physios * 0.6); state.fitness -= Math.max(1, drain); let eventRoll = Math.random(); if (eventRoll < 0.10 - (state.physios * 0.02)) { let pool = playersDB[Math.min(state.leagueLvl, 4)].names; ticker(`Injury blow! <strong>${pool[0]}</strong> strains hamstrings.`, "orange"); state.fitness -= 18; } else if (state.year === 2013 && state.week === 20 && state.leagueLvl === 0) { ticker("John Still instills ruthless fitness principles.", "orange"); state.quality += 15; } else if (state.year === 2023 && state.week === 35 && state.leagueLvl === 3) { ticker("Rob Edwards pushes standard tactics over the edge!", "orange"); state.quality += 20; } let performanceScore = state.quality; if(state.fitness < 30) performanceScore *= 0.5; let calculation = (performanceScore / lData.minQuality) * 0.45 + (state.fitness / 100) * 0.2 + (Math.random() * 0.35); let resText = ""; let ptsText = ""; if (state.fitness <= 0) { ticker("Fatigue emergency. Fielded academy scholars.", "orange"); resText = "LOSS"; ptsText = "0 Points Secured"; state.fitness = 10; } else if (calculation > 0.62) { state.points += 3; resText = "WIN"; ptsText = "+3 Points Added"; ticker(`Full time! Excellent victory recorded.`); } else if (calculation > 0.36) { state.points += 1; resText = "DRAW"; ptsText = "+1 Point Earned"; ticker(`Full time! Spoil of the points split.`); } else { resText = "LOSS"; ptsText = "0 Points Secured"; ticker(`Full time. Tough defeat for the boys.`); } drawMatchResult(resText, ptsText); state.week++; if (state.funds < -400) { endGame("ADMINISTRATION. Debt margin surpassed. The High Court forced asset liquidation."); return; } if (state.week > 46) { handleSeasonEnd(lData); } else { updateUI(); } }); } function handleSeasonEnd(lData) { ticker(`--- FINALE OF THE ${state.year} YEAR ---`, "orange"); if (state.points >= lData.target) { if (state.leagueLvl === 4) { endGame("PREMIER LEAGUE SUCCESS! Gary Sweet, you took Luton from -30 non-league humiliation right back to world elite. Legend status confirmed."); return; } else { state.leagueLvl++; ticker(`PROMOTION ATTAINED! Welcome to ${leagues[state.leagueLvl].name}!`, "orange"); state.funds += leagues[state.leagueLvl].tvMoney; } } else if (state.points < lData.target - 25 && state.leagueLvl > 0) { state.leagueLvl--; ticker("RELEGATED! Boardroom executives demand answers.", "orange"); } else { ticker("Target parameters missed. Better luck next time out.", "blue"); state.funds += lData.tvMoney * 0.25; } state.year++; state.week = 1; state.points = 0; state.fitness = 100; let churn = Math.floor(Math.random() * 3) + 3; state.squadSize = Math.max(12, state.squadSize - churn); state.wages = Math.max(10, state.wages - (churn * 2)); state.quality = Math.max(25, state.quality - (churn * 4)); ticker(`Contract churn: ${churn} players left on free transfers over the summer.`, "blue"); updateUI(); drawScene('ready'); } function endGame(msg) { state.gameOver = true; document.getElementById('main-layout-wrapper').style.display = 'none'; document.getElementById('screen-end').style.display = 'block'; document.getElementById('end-text').innerText = msg; } </script> </body> </html>
COYH