forms

Roadrash 2002 Shit Graphics

Retro Road Racer: Combat Velocity

Retro Road Racer is a high-speed, 16-bit inspired combat racing game that pays homage to the legendary arcade "super-scaler" titles of the early 90s. Combining pixel-perfect aesthetics with modern fluid performance, it places players in the seat of a heavy-duty racing motorcycle on a lawless stretch of highway.

Core Gameplay

The objective is simple but brutal: reach the finish line of a 500-segment track while navigating hazardous curves, elevation changes, and aggressive rivals. Unlike traditional racers, finishing first requires more than just speed—it requires physical dominance.

Key Features

Heavy-Bore Combat: Your bike is equipped for more than just racing. Use the Kick mechanic to physically displace rivals as you pull alongside them. Timing is critical; a well-placed strike can send an opponent careening off the track, while a miss leaves you vulnerable.

Pseudo-3D Engine: Experience a custom-built "super-scaler" rendering engine that simulates 3D depth using 2D sprites. The track features dynamic hills, valleys, and sharp curves that challenge your bike's lean physics and traction.

Dynamic HUD & Feedback: * Integrity Meter: Monitors your bike’s health. Sustaining damage from collisions or environmental hazards will lead to total mechanical failure.

Precision Gauges: Real-time MPH tracking and distance-to-finish markers keep you informed in the heat of the race.

Responsive Physics: Master the lean. High-speed cornering requires careful positioning. Over-steering or failing to hit the apex of a curve will slow your momentum and leave you open to counter-attacks.

Old-School Aesthetics: * Vibrant, pixelated environments with parallax mountain ranges.

Detailed "heavy" bike sprites featuring visible engine blocks, aerodynamic cowls, and riders in full racing leathers.

A high-contrast color palette optimized for that classic arcade feel.

Controls

Action

Keyboard

Touch (Mobile)

Accelerate

Up Arrow

"GO" Button

Brake

Down Arrow



Steer

Left / Right Arrows

"L" / "R" Buttons

Kick Attack

Spacebar

"K" Button

Retro Road Racer is an unforgiving test of reflexes and aggression. Whether you’re weaving through traffic or kicking your way to the front of the pack, only the most ruthless riders will see the checkered flag.

Code Snippet

<!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>Retro Road Racer - Pixel Perfect</title>
    <style>
        @font-face {
            font-family: 'Retro';
            src: url('https://fonts.cdnfonts.com/s/16219/PressStart2P-Regular.woff');
        }

        body {
            margin: 0;
            padding: 0;
            background: #000;
            color: #fff;
            font-family: 'Press Start 2P', 'Courier New', monospace;
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            image-rendering: pixelated;
        }

        #game-wrapper {
            position: relative;
            width: 800px;
            height: 800px;
            display: flex;
            flex-direction: column;
            background: #000;
        }

        canvas {
            width: 800px;
            height: 500px;
            background: #111;
            image-rendering: pixelated;
            border-top: 4px solid #fbbf24;
            border-bottom: 4px solid #fbbf24;
        }

        .hud-top {
            height: 80px;
            display: flex;
            justify-content: space-around;
            align-items: center;
            background: #000;
        }

        .hud-bottom {
            flex-grow: 1;
            background: #000;
            padding: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .retro-box {
            border: 3px solid #fbbf24;
            border-radius: 12px;
            padding: 8px 15px;
            background: #000;
            color: #fff;
            font-size: 14px;
            font-weight: bold;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .integrity-section {
            display: flex;
            flex-direction: column;
            gap: 5px;
        }

        .bar-outer {
            width: 150px;
            height: 12px;
            border: 2px solid #fff;
            background: #222;
        }

        #health-bar {
            width: 100%;
            height: 100%;
            background: linear-gradient(to bottom, #f97316, #ea580c);
        }

        .center-title {
            text-align: center;
        }

        .center-title h1 {
            color: #fbbf24;
            margin: 0;
            font-size: 28px;
            font-style: italic;
        }

        .speed-gauge {
            border: 3px solid #fbbf24;
            border-radius: 10px;
            padding: 10px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        #speed-val { font-size: 32px; }

        #overlay {
            position: absolute;
            inset: 80px 0 220px 0;
            background: rgba(0,0,0,0.6);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 100;
        }

        .btn-start {
            background: #fbbf24;
            color: #000;
            border: none;
            padding: 15px 40px;
            font-family: inherit;
            font-size: 20px;
            cursor: pointer;
            box-shadow: 4px 4px 0 #b45309;
        }

        .touch-controls {
            position: fixed;
            bottom: 20px;
            width: 100%;
            display: none;
            justify-content: space-between;
            padding: 0 40px;
            pointer-events: none;
        }

        .t-btn {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            background: rgba(255,255,255,0.2);
            border: 3px solid #fff;
            pointer-events: auto;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
        }

        @media (max-width: 800px) {
            .touch-controls { display: flex; }
            #game-wrapper { width: 100vw; height: 100vh; }
            canvas { width: 100%; height: auto; }
        }
    </style>
</head>
<body>

    <div id="game-wrapper">
        <div class="hud-top">
            <div class="retro-box">LEVEL 1</div>
            <div class="retro-box" id="hud-pos">POS 1/12</div>
            <div class="retro-box" id="hud-finish">FINISH 0m</div>
            <div class="retro-box" id="hud-dist">DIST 0m</div>
        </div>

        <canvas id="gameCanvas"></canvas>

        <div class="hud-bottom">
            <div class="integrity-section">
                <span style="font-size: 10px;">INTEGRITY</span>
                <div class="bar-outer"><div id="health-bar"></div></div>
            </div>

            <div class="center-title">
                <h1>ROAD RASH</h1>
                <div style="font-size: 8px; color: #aaa; margin-top: 5px;">sub-tile, and survive!</div>
                <button class="btn-start" id="startBtn" onclick="startGame()" style="margin-top: 15px; font-size: 12px; padding: 10px 20px;">Start Race</button>
            </div>

            <div class="speed-gauge">
                <span id="speed-val">0</span>
                <span style="font-size: 10px;">MPH</span>
            </div>
        </div>

        <div id="overlay"></div>

        <div class="touch-controls">
            <div style="display:flex; gap:10px;"><div class="t-btn" id="t-l">L</div><div class="t-btn" id="t-r">R</div></div>
            <div style="display:flex; gap:10px;"><div class="t-btn" id="t-k" style="color:red">K</div><div class="t-btn" id="t-g" style="color:green">GO</div></div>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const width = 400, height = 250;
        canvas.width = width; canvas.height = height;

        const roadWidth = 1800;
        const segmentLength = 200;
        const cameraHeight = 1000;
        const cameraDepth = 1 / Math.tan((80 * Math.PI / 180) / 2);
        const drawDistance = 300;
        const playerZ = cameraHeight * cameraDepth;

        let segments = [];
        let player = { x: 0, z: 0, speed: 0, maxSpeed: 16000, accel: 4500, health: 100, kick: 0, kickT: 0, lean: 0 };
        let trackLength = 0;
        let keys = {};
        let enemies = [];
        let gameState = 'menu';
        let lastTime = 0;

        function addSegment(curve, y) {
            let n = segments.length;
            let startY = n > 0 ? segments[n-1].p2.world.y : 0;
            segments.push({
                index: n,
                p1: { world: { x: 0, y: startY, z: n * segmentLength }, camera: {}, screen: {} },
                p2: { world: { x: 0, y: y, z: (n + 1) * segmentLength }, camera: {}, screen: {} },
                curve: curve, 
                grass: Math.floor(n / 3) % 2 ? '#e2e8f0' : '#cbd5e1',
                road: Math.floor(n / 3) % 2 ? '#444' : '#3d3d3d',
                objects: []
            });
        }

        function resetTrack() {
            segments = [];
            for(let i=0; i<500; i++) {
                addSegment(Math.sin(i/30)*3, Math.sin(i/40)*1500);
                if (i % 5 === 0) {
                    segments[i].objects.push({ x: -2.5 - Math.random(), type: 'tree' });
                    segments[i].objects.push({ x: 2.5 + Math.random(), type: 'tree' });
                }
            }
            trackLength = segments.length * segmentLength;
            enemies = [];
            const enemyColors = ['#ef4444', '#3b82f6', '#10b981', '#a855f7', '#f97316', '#ec4899'];
            for(let i=0; i<11; i++) {
                enemies.push({ 
                    z: 2000 + i*4000, 
                    x: (Math.random()*1.4)-0.7, 
                    speed: 8000 + Math.random()*4000, 
                    color: enemyColors[i % enemyColors.length], 
                    dead: false 
                });
            }
        }

        function project(p, cameraX, cameraY, cameraZ) {
            p.camera.x = p.world.x - cameraX; 
            p.camera.y = p.world.y - cameraY; 
            p.camera.z = p.world.z - cameraZ;
            
            if (p.camera.z <= 0) {
                p.screen.scale = 0;
                return;
            }
            
            p.screen.scale = cameraDepth / p.camera.z;
            p.screen.x = Math.round((width / 2) + (p.screen.scale * p.camera.x * width / 2));
            p.screen.y = Math.round((height / 2) - (p.screen.scale * p.camera.y * height / 2));
            p.screen.w = Math.round(p.screen.scale * roadWidth * width / 2);
        }

        function drawTree(x, y, scale) {
            const w = 150 * scale, h = 400 * scale;
            if (h < 1) return;
            ctx.fillStyle = '#2d3748'; 
            ctx.fillRect(x - w*0.1, y - h*0.2, w*0.2, h*0.2);
            ctx.fillStyle = '#065f46';
            ctx.beginPath(); 
            ctx.moveTo(x - w*0.6, y - h*0.2); 
            ctx.lineTo(x + w*0.6, y - h*0.2); 
            ctx.lineTo(x, y - h); 
            ctx.fill();
            ctx.fillStyle = '#fff'; 
            ctx.fillRect(x - w*0.4, y - h*0.22, w*0.8, h*0.05);
        }

        function drawBike(x, y, scale, color, kick = 0, isDead = false, lean = 0) {
            ctx.save();
            ctx.translate(x, y);
            const s = scale * 160; // Increased size to match "heavy" look
            if (s < 1) { ctx.restore(); return; }
            if(isDead) { ctx.rotate(Math.PI/2); ctx.translate(0, -s*0.3); }
            else { ctx.rotate(lean * 0.15); }

            // Ground Shadow
            ctx.fillStyle = 'rgba(0,0,0,0.4)';
            ctx.beginPath(); ctx.ellipse(0, 0, s*0.45, s*0.1, 0, 0, Math.PI*2); ctx.fill();

            // REAR WHEEL (Thick and dark)
            ctx.fillStyle = '#000';
            ctx.fillRect(-s*0.25, -s*0.4, s*0.5, s*0.4);
            ctx.fillStyle = '#1a1a1a';
            ctx.fillRect(-s*0.15, -s*0.3, s*0.3, s*0.2);

            // REAR SWINGARM & EXHAUST
            ctx.fillStyle = '#333';
            ctx.fillRect(-s*0.3, -s*0.45, s*0.15, s*0.2); // Muffler
            ctx.fillStyle = '#444';
            ctx.fillRect(s*0.1, -s*0.35, s*0.15, s*0.08); // Exhaust tip

            // ENGINE BLOCK
            ctx.fillStyle = '#222';
            ctx.fillRect(-s*0.2, -s*0.65, s*0.4, s*0.25);
            ctx.fillStyle = '#333';
            ctx.fillRect(-s*0.15, -s*0.6, s*0.3, s*0.1); // Fins

            // MAIN BODYWORK (The heavy aerodynamic shell)
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.moveTo(-s*0.35, -s*0.85); // Back seat
            ctx.lineTo(s*0.35, -s*0.85);  // Front cowl
            ctx.lineTo(s*0.25, -s*0.4);   // Bottom front
            ctx.lineTo(-s*0.25, -s*0.4);  // Bottom back
            ctx.fill();

            // FRONT WINDSCREEN / DEFLECTOR
            ctx.fillStyle = '#111'; // Dark plastic
            ctx.fillRect(s*0.05, -s*0.92, s*0.25, s*0.1);

            // HANDLEBARS / FORKS
            ctx.fillStyle = '#111';
            ctx.fillRect(s*0.1, -s*1.05, s*0.25, s*0.05); // Bars
            ctx.fillStyle = '#333';
            ctx.fillRect(s*0.2, -s*0.8, s*0.05, s*0.5); // Fork tube

            // RIDER (Tucked in)
            ctx.fillStyle = '#111'; // Leathers
            ctx.beginPath();
            ctx.moveTo(-s*0.25, -s*0.85);
            ctx.lineTo(s*0.1, -s*0.85);
            ctx.lineTo(s*0.05, -s*1.3);
            ctx.lineTo(-s*0.2, -s*1.2);
            ctx.fill();

            // HELMET
            ctx.fillStyle = color;
            ctx.beginPath();
            ctx.arc(-s*0.05, -s*1.4, s*0.14, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = '#000'; // Visor
            ctx.fillRect(-s*0.1, -s*1.45, s*0.2, s*0.08);

            // KICK ATTACK
            if(kick > 0) {
                ctx.fillStyle = '#000'; // Leg
                ctx.fillRect(s*0.2, -s*0.7, s*0.8, s*0.15);
                ctx.fillStyle = '#111'; // Boot
                ctx.fillRect(s*0.85, -s*0.75, s*0.15, s*0.2);
            }

            ctx.restore();
        }

        function update(dt) {
            if (gameState !== 'playing') return;
            
            if (keys['ArrowUp'] || keys['gas']) player.speed += player.accel * dt;
            else if (keys['ArrowDown']) player.speed -= 10000 * dt;
            else player.speed -= 2000 * dt;

            player.lean = 0;
            if (keys['ArrowLeft'] || keys['left']) { player.x -= 2.5 * dt; player.lean = -1; }
            if (keys['ArrowRight'] || keys['right']) { player.x += 2.5 * dt; player.lean = 1; }

            if ((keys[' '] || keys['kick']) && player.kickT <= 0) { player.kick = 1; player.kickT = 0.4; }
            if (player.kickT > 0) { player.kickT -= dt; if(player.kickT <= 0) player.kick = 0; }

            player.speed = Math.max(0, Math.min(player.speed, player.maxSpeed));
            player.z += player.speed * dt;
            
            if (player.z >= trackLength) {
                player.z = 0; // Win condition or loop
            }

            let playerPos = 12;
            enemies.forEach(e => {
                if(!e.dead) {
                    e.z += e.speed * dt;
                    if(e.z > trackLength) e.z -= trackLength;
                    if(e.z < player.z) playerPos--;
                    
                    if(Math.abs(player.z - e.z) < 250 && Math.abs(player.x - e.x) < 0.4 && player.kick) e.dead = true;
                } else {
                    playerPos--;
                }
            });

            document.getElementById('speed-val').innerText = Math.floor(player.speed / 100);
            document.getElementById('health-bar').style.width = player.health + '%';
            document.getElementById('hud-finish').innerText = `FINISH ${Math.max(0, Math.floor((trackLength - player.z)/100))}m`;
            document.getElementById('hud-dist').innerText = `DIST ${Math.floor(player.z/100)}m`;
            document.getElementById('hud-pos').innerText = `POS ${playerPos}/12`;

            if (player.health <= 0) {
                gameState = 'menu';
                document.getElementById('overlay').style.display = 'flex';
                document.getElementById('startBtn').style.display = 'block';
            }
        }

        function render() {
            ctx.clearRect(0,0,width,height);
            
            // Sky & Mountains
            ctx.fillStyle = '#7dd3fc'; ctx.fillRect(0,0,width,height/2);
            for(let i=0; i<6; i++) {
                ctx.fillStyle = '#94a3b8';
                ctx.beginPath(); 
                ctx.moveTo(i*100-80, height/2); 
                ctx.lineTo(i*100+20, height/2-80); 
                ctx.lineTo(i*100+120, height/2); 
                ctx.fill();
            }

            if (segments.length === 0) return;

            let baseIdx = Math.floor(player.z / segmentLength) % segments.length;
            let percent = (player.z % segmentLength) / segmentLength;
            
            let startSeg = segments[baseIdx];
            if (!startSeg) return;

            let playerY = startSeg.p1.world.y + (startSeg.p2.world.y - startSeg.p1.world.y) * percent;
            let x = 0, dx = -(startSeg.curve * percent);
            
            for (let n = 0; n < drawDistance; n++) {
                let s = segments[(baseIdx + n) % segments.length];
                if (!s) continue;
                
                project(s.p1, player.x * roadWidth - x, playerY + cameraHeight, player.z);
                project(s.p2, player.x * roadWidth - x - dx, playerY + cameraHeight, player.z);
                
                x += dx; 
                dx += s.curve;
                
                if (s.p1.camera.z <= 0) continue;

                ctx.fillStyle = s.grass;
                ctx.fillRect(0, s.p2.screen.y, width, s.p1.screen.y - s.p2.screen.y);
                
                let p1 = s.p1.screen, p2 = s.p2.screen;
                ctx.fillStyle = s.road;
                ctx.beginPath(); 
                ctx.moveTo(p1.x-p1.w, p1.y); 
                ctx.lineTo(p2.x-p2.w, p2.y); 
                ctx.lineTo(p2.x+p2.w, p2.y); 
                ctx.lineTo(p1.x+p1.w, p1.y); 
                ctx.fill();
                
                if (s.index % 6 < 3) {
                    ctx.fillStyle = '#fff';
                    ctx.beginPath(); 
                    ctx.moveTo(p1.x-p1.w*0.02, p1.y); 
                    ctx.lineTo(p2.x-p2.w*0.02, p2.y); 
                    ctx.lineTo(p2.x+p2.w*0.02, p2.y); 
                    ctx.lineTo(p1.x+p1.w*0.02, p1.y); 
                    ctx.fill();
                }
            }

            for (let n = drawDistance - 1; n >= 0; n--) {
                let s = segments[(baseIdx + n) % segments.length];
                if (!s) continue;
                
                let scale = s.p1.screen.scale * width/2;
                
                s.objects.forEach(o => {
                    if (o.type === 'tree') drawTree(s.p1.screen.x + (s.p1.screen.w * o.x), s.p1.screen.y, scale/1000);
                });

                enemies.forEach(e => {
                    if (Math.floor(e.z / segmentLength) === s.index) {
                        let p = { world: { x: e.x*roadWidth, y: s.p1.world.y, z: e.z }, camera: {}, screen: {} };
                        project(p, player.x * roadWidth, playerY + cameraHeight, player.z);
                        if (p.camera.z > 0) drawBike(p.screen.x, p.screen.y, p.screen.scale * width/2, e.color, 0, e.dead);
                    }
                });
            }
            
            drawBike(width/2, height - 10, (cameraDepth/playerZ)*(width/2), '#fbbf24', player.kick, false, player.lean);
        }

        function startGame() {
            resetTrack(); 
            player.z = 0; 
            player.health = 100; 
            player.speed = 0;
            gameState = 'playing'; 
            document.getElementById('overlay').style.display = 'none';
            document.getElementById('startBtn').style.display = 'none';
            lastTime = performance.now(); 
            gameLoop();
        }

        function gameLoop() {
            let now = performance.now(); 
            update((now-lastTime)/1000); 
            render();
            lastTime = now; 
            if(gameState === 'playing') requestAnimationFrame(gameLoop);
        }

        window.addEventListener('keydown', e => keys[e.key] = true);
        window.addEventListener('keyup', e => keys[e.key] = false);
        
        const touch = (id, k) => {
            const el = document.getElementById(id);
            if (!el) return;
            el.addEventListener('touchstart', e => { e.preventDefault(); keys[k] = true; });
            el.addEventListener('touchend', e => { e.preventDefault(); keys[k] = false; });
        }
        touch('t-l', 'left'); touch('t-r', 'right'); touch('t-g', 'gas'); touch('t-k', 'kick');
        
        resetTrack();
        render();
    </script>
</body>
</html>

Media & Assets

Roadrash 2002 Shit Graphics
Resource ID: #00035
Posted: December 23, 2025
© 2025 Your Code Library.