← back to Model Arena

data/artifacts/035b7009e366/gemma3-12b.html

339 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Designer Wallcoverings - Endless Runner</title>
    <style>
        :root {
            --bg: #faf8f4;
            --surface: #ffffff;
            --text: #1c1a17;
            --muted: #9b948a;
            --accent: #b0472e;
            --line: #dcdcdc;
            --shadow: rgba(0, 0, 0, 0.12);
            --ease: cubic-bezier(.22,1,.36,1);
        }

        body {
            margin: 0;
            overflow: hidden;
            background-color: var(--bg);
            font-family: 'apple-system', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
            color: var(--text);
            display: flex;
            flex-direction: column;
            height: 100vh;
        }

        .top-bar {
            background-color: var(--surface);
            padding: 24px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
            display: flex;
            align-items: center;
        }

        .wordmark {
            font-family: 'Playfair Display', Georgia, serif;
            font-size: 48px; /*Adjust size to fit*/
            letter-spacing: .18em;
            text-transform: uppercase;
            display: inline-block;
        }

        canvas {
            background-color: var(--surface);
            display: block;
        }

        .game-over-screen, .win-screen {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.9);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 10;
        }

        .game-over-screen h1, .win-screen h1 {
            font-family: 'Playfair Display', Georgia, serif;
            font-size: 48px;
            margin-bottom: 24px;
            text-align: center;
        }

        .game-over-screen p, .win-screen p{
          font-size: 16px;
          text-align: center;
          margin-bottom: 32px;
        }


        .restart-button, .continue-button {
            background-color: var(--accent);
            color: white;
            padding: 12px 24px;
            border: none;
            font-size: 14px;
            text-transform: uppercase;
            letter-spacing: .15em;
            cursor: pointer;
            margin-top: 32px;
            width: 200px; /* Fixed width */
        }

        .score-board {
          position: fixed;
          bottom: 16px;
          right: 16px;
          background-color: rgba(255, 255, 255, 0.8);
          padding: 8px 16px;
          border-radius: 8px;
          box-shadow: 0 2px 4px var(--shadow);
          font-size: 12px;
          text-transform: uppercase;
          letter-spacing: .15em;
        }

    </style>
</head>
<body>

    <div class="top-bar">
        <div class="wordmark">DESIGNER WALLCOVERINGS</div>
    </div>

    <canvas id="gameCanvas" width="400" height="600"></canvas>
    <div class="score-board" id="scoreboard">SCORE: 0 | BEST: 0</div>


    <div class="game-over-screen" id="gameOverScreen">
        <h1>GAME OVER</h1>
        <p>Your wallcovering design journey has ended.</p>
        <button class="restart-button" onclick="restartGame()">RESTART</button>
    </div>

     <div class="win-screen" id="winScreen" style="display:none;">
        <h1>YOU WIN!</h1>
        <p>Your wallcovering design is a masterpiece!</p>
        <button class="continue-button" onclick="restartGame()">CONTINUE</button>
    </div>


    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        let rollerX = 50;
        let rollerY = canvas.height - 100;
        const rollerWidth = 30;
        const rollerHeight = 40;
        let rollerVelocityY = 0;
        const gravity = 0.6;
        const jumpForce = -15;

        let wallpaperRolls = [];
        const wallpaperSpeed = 5;
        let score = 0;
        let bestScore = localStorage.getItem('bestScore') || 0;

        let obstacles = [];
        const obstacleSpawnRate = 120; // Frames per spawn (adjust for difficulty)
        let obstacleTimer = 0;

        const wallpaperStyles = ['floral', 'geometric', 'abstract', 'striped'];  //For visual distinction


        function createWallpaperRoll() {
            const styleIndex = Math.floor(Math.random() * wallpaperStyles.length);
            wallpaperRolls.push({
                x: canvas.width,
                y: rollerY - 20,
                style: wallpaperStyles[styleIndex]
            });
        }

        function createObstacle() {
          const obstacleType = Math.random() < 0.5 ? 'pillar' : 'beam'; // Randomize obstacle type
            obstacles.push({
                x: canvas.width,
                y: rollerY - 30,
                type: obstacleType
            });
        }


        function updateScoreboard(){
            document.getElementById('scoreboard').innerText = `SCORE: ${score} | BEST: ${bestScore}`;
        }

        function restartGame() {
            rollerX = 50;
            rollerY = canvas.height - 100;
            rollerVelocityY = 0;
            wallpaperRolls = [];
            obstacles = [];
            score = 0;
            updateScoreboard();
            document.getElementById('gameOverScreen').style.display = 'none';
            document.getElementById('winScreen').style.display = 'none';
            animate(); // Restart the animation loop
        }



        function drawWallpaperRoll(roll) {
          let styleImage;

          switch (roll.style){
            case "floral": styleImage="url('data:image/svg+xml,%3Csvg width%3D20 height%3D20 viewBox%3D0 0 20 20 fill%3Dnone xmlns%3Dhttp://www.w3.org/2000/svg%3E%3Cpath d%3D\"M10 4a2 2 0 01-2 0q0 1.1111107-0.8888929 1.6111071L5.6111071 11.388893a2 2 0 01-2 0l-4.22222-4.22222q-.8888929 0-1.6111071-.8888929L2 7.22222a2 2 0 010-4l3.5555556-3.5555556q.8888929 0 1.6111071.8888929L10 4Z\" fill%3D#c9a961/0.3%3E%3C/path%3E%3C/svg%3E')"; break;
            case "geometric": styleImage="url('data:image/svg+xml,%3Csvg width%3D20 height%3D20 viewBox%3D0 0 20 20 fill%3Dnone xmlns%3Dhttp://www.w3.org/2000/svg%3E%3Crect x%3D4 y%3D4 width%3D12 height%3D12 stroke%3D#c9a961 stroke-width%3D2%3E%3C/rect%3E%3C/svg%3E')"; break;
            case "abstract": styleImage="url('data:image/svg+xml,%3Csvg width%3D20 height%3D20 viewBox%3D0 0 20 20 fill%3Dnone xmlns%3Dhttp://www.w3.org/2000/svg%3E%3Ccircle cx%3D10 cy%3D10 r%3D8 fill%3D#c9a961/0.5%3E%3C/circle%3E%3C/svg%3E')"; break;
            case "striped": styleImage="url('data:image/svg+xml,%3Csvg width%3D20 height%3D20 viewBox%3D0 0 20 20 fill%3Dnone xmlns%3Dhttp://www.w3.org/2000/svg%3E%3Crect x%3D0 y%3D0 width%3D20 height%3D5 style%3D\"fill:%23c9a961;\"%3E%3C/rect%3E%3Crect x%3D0 y%3D5 width%3D20 height%3D5 style%3D\"fill:%23faf8f4;\"%3E%3C/rect%3E%3Crect x%3D0 y%3D10 width%3D20 height%3D5 style%3D\"fill:%23c9a961;\"%3E%3C/rect%3E%3C/svg%3E')"; break;
          }

            ctx.drawImage(new Image(), 0, 0, 20, 20); //This is a placeholder to get the css working.  Replace with loadStyleImage
        }


        function drawObstacle(obstacle) {
           if (obstacle.type === 'pillar') {
                ctx.fillStyle = '#a1c4d3'; // Blue pillar color
                ctx.fillRect(obstacle.x, obstacle.y, 20, 50);
            } else if (obstacle.type === 'beam') {
                ctx.strokeStyle = '#a1c4d3'; // Blue beam color
                ctx.lineWidth = 5;
                ctx.beginPath();
                ctx.moveTo(obstacle.x, obstacle.y + 20);
                ctx.lineTo(obstacle.x + 30, obstacle.y + 20);
                ctx.stroke();
            }
        }



        function animate() {

            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, canvas.width, canvas.height);


            // Roller Movement
            rollerVelocityY += gravity;
            rollerY += rollerVelocityY;

            if (rollerY > canvas.height - rollerHeight) {
                rollerY = canvas.height - rollerHeight;
                rollerVelocityY = 0;
            }



             // Wallpaper Rolls
            for (let i = 0; i < wallpaperRolls.length; i++) {
                drawWallpaperRoll(wallpaperRolls[i]);
                wallpaperRolls[i].x -= wallpaperSpeed;

                if (wallpaperRolls[i].x < 0) {
                    wallpaperRolls.splice(i, 1);
                    score++;
                }

                 if (rollerX > wallpaperRolls[i].x -15 && rollerX < wallpaperRolls[i].x + 15 &&  rollerY < wallpaperRolls[i].y + 20 && rollerY > wallpaperRolls[i].y - 20) {
                    // Collision with wallpaper roll (collect!)
                   wallpaperRolls.splice(i, 1); // Remove collected roll

                 }
            }



             // Obstacles
            for (let i = 0; i < obstacles.length; i++) {
                drawObstacle(obstacles[i]);
                obstacles[i].x -= wallpaperSpeed;

                if (obstacles[i].x < 0) {
                    obstacles.splice(i, 1);
                }

                 if (rollerX > obstacles[i].x -15 && rollerX < obstacles[i].x + 15 &&  rollerY < obstacles[i].y + 30 && rollerY > obstacles[i].y - 30) {
                    // Collision with obstacle (game over!)
                     showGameOverScreen();
                     return; // End the game
                 }

            }


            if(score > bestScore){
                bestScore = score;
                localStorage.setItem('bestScore', bestScore);
                updateScoreboard()
            }



             // Create new wallpaper rolls and obstacles
            if (obstacleTimer % obstacleSpawnRate === 0) {
                createObstacle();
            }

            if(wallpaperRolls.length < 3){ //Limit number of rolls on screen to avoid clutter
              if(Math.random() < .15){
                  createWallpaperRoll();
              }
            }


            ctx.fillText(`Score: ${score}`, 10, 20);

            // Draw the roller
            ctx.fillStyle = '#c9a961';
            ctx.fillRect(rollerX, rollerY, rollerWidth, rollerHeight);



        }


       function showGameOverScreen() {
           document.getElementById('gameOverScreen').style.display = 'flex';
       }

        // Initial game setup
        let animationFrameId;
        function startGame(){
            animationFrameId = requestAnimationFrame(animate);
            updateScoreboard();
        }


        window.addEventListener('keydown', (e) => {
            if (e.code === 'Space' || e.code === 'ArrowUp') {
                if (rollerY > canvas.height - rollerHeight) {
                    rollerVelocityY = jumpForce;
                }
            }
        });

        canvas.addEventListener('click', () => { // Mobile Tap support
            if (rollerY > canvas.height - rollerHeight) {
                rollerVelocityY = jumpForce;
            }
        });

         startGame();


    </script>
</body>
</html>