<!DOCTYPE html>
<html>
<head>

    <title>3D Runner Game</title>
    <meta charset="utf-8">

   <script>
        function isMobile() {
            return /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
        }

        function checkDeviceAndRedirect() {
            if (isMobile()) {
                // Redirect mobile users to the specified URL
                window.location.href = "https://itsrealm12c.github.io/3dcuberunner/mo";
            }
        }

        // Call the function to check device type and possibly redirect
        checkDeviceAndRedirect();
    </script>
    
   
    
    <style>
        body { margin: 0; overflow: hidden; }
        #score {
            position: fixed;
            top: 20px;
            left: 20px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 24px;
            z-index: 100;
        }
        #gameOver {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-family: Arial, sans-serif;
            font-size: 48px;
            display: none;
            text-align: center;
            z-index: 100;
        }
        #gameOver button {
            padding: 10px 20px;
            font-size: 24px;
            margin-top: 20px;
            cursor: pointer;
        }
        #preview {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 200px;
            height: 150px;
            border: 2px solid white;
            z-index: 100;
        }
        #timer {
            position: fixed;
            bottom: 20px;
            left: 20px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 24px;
            z-index: 100;
            display: none;
        }
    </style>
</head>
<body>
    <div id="score">Score: 0</div>
    <div id="gameOver">
        Game Over!
        <br>
        <button onclick="restartGame()">Restart</button>
    </div>
    <div id="preview"></div>
    <div id="timer">Quadruple Jump: 10s</div>
    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/three@0.159.0/build/three.module.js",
                "three/addons/": "https://unpkg.com/three@0.159.0/examples/jsm/"
            }
        }
    </script>
    <script type="module">
        import * as THREE from 'three';

        let scene, camera, renderer, player;
        let obstacles = [];
        let platforms = [];
        let blueBlocks = [];  
        let yellowBlocks = [];  
        let orangeBlocks = [];  
        let purpleBlocks = [];  
        let gameSpeed = 0.2;
        let score = 0;
        let isGameOver = false;
        let playerVelocity = 0;
        let isJumping = false;
        let moveLeft = false;
        let moveRight = false;
        let maxJumps = 1;      
        let jumpCount = 0;     
        const MOVEMENT_SPEED = 0.15;
        const PLATFORM_WIDTH = 5;
        let previewCamera, previewRenderer;
        let previewPlayer;
        let powerUpTimer = null;
        let remainingTime = 10;

        function init() {
            scene = new THREE.Scene();
            
            const loader = new THREE.CubeTextureLoader();
            const skyboxTexture = new THREE.Color(0x87CEEB); 
            scene.background = skyboxTexture;

            for(let i = 0; i < 20; i++) {
                const cloudGeometry = new THREE.SphereGeometry(2, 16, 16);
                const cloudMaterial = new THREE.MeshBasicMaterial({ 
                    color: 0xffffff,
                    transparent: true,
                    opacity: 0.8
                });
                const cloud = new THREE.Mesh(cloudGeometry, cloudMaterial);
                cloud.position.set(
                    (Math.random() - 0.5) * 100,
                    20 + (Math.random() - 0.5) * 10,
                    (Math.random() - 0.5) * 100
                );
                cloud.scale.set(1, 0.3, 1);
                scene.add(cloud);
            }

            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            
            renderer = new THREE.WebGLRenderer();
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);
            
            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(10, 20, 0);
            scene.add(directionalLight);

            const playerGeometry = new THREE.BoxGeometry(1, 1, 1);
            const playerMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
            player = new THREE.Mesh(playerGeometry, playerMaterial);
            player.position.set(0, 1, 0);
            scene.add(player);

            const previewGeometry = new THREE.BoxGeometry(1, 1, 1);
            const previewMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
            previewPlayer = new THREE.Mesh(previewGeometry, previewMaterial);
            previewPlayer.position.copy(player.position);
            scene.add(previewPlayer);

            camera.position.set(0, 3, 7);
            camera.lookAt(player.position);

            createInitialPlatforms();
            
            document.addEventListener('keydown', onKeyDown);
            document.addEventListener('keyup', onKeyUp);
            
            // Setup preview
            previewCamera = new THREE.OrthographicCamera(
                -5, 5,
                3.75, -3.75,
                0.1, 1000
            );
            previewCamera.position.set(0, 10, 0);
            previewCamera.lookAt(0, 0, 0);
            previewCamera.rotation.z = Math.PI;

            previewRenderer = new THREE.WebGLRenderer();
            previewRenderer.setSize(200, 150);
            const previewContainer = document.getElementById('preview');
            previewContainer.appendChild(previewRenderer.domElement);

            animate();
        }

        function createInitialPlatforms() {
            for (let i = 0; i < 5; i++) {
                createPlatform(-20 * i);
            }
        }

        function createPlatform(zPosition) {
            const platformGeometry = new THREE.BoxGeometry(5, 0.5, 20);
            
            const canvas = document.createElement('canvas');
            canvas.width = 256;
            canvas.height = 256;
            const context = canvas.getContext('2d');

            const tileSize = 32;
            for (let x = 0; x < canvas.width; x += tileSize) {
                for (let y = 0; y < canvas.height; y += tileSize) {
                    context.fillStyle = ((x + y) / tileSize) % 2 === 0 ? '#808080' : '#606060';
                    context.fillRect(x, y, tileSize, tileSize);

                    context.fillStyle = 'rgba(0,0,0,0.1)';
                    for (let i = 0; i < 5; i++) {
                        context.fillRect(
                            x + Math.random() * tileSize,
                            y + Math.random() * tileSize,
                            2,
                            2
                        );
                    }
                }
            }

            const texture = new THREE.CanvasTexture(canvas);
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.repeat.set(2, 8);

            const platformMaterial = new THREE.MeshPhongMaterial({ 
                map: texture,
                bumpMap: texture,
                bumpScale: 0.05
            });

            const platform = new THREE.Mesh(platformGeometry, platformMaterial);
            platform.position.set(0, -0.25, zPosition);
            scene.add(platform);
            platforms.push(platform);

            if (Math.random() > 0.3) {
                const obstacleGeometry = new THREE.BoxGeometry(1, 1, 1);
                const obstacleMaterial = new THREE.MeshPhongMaterial({ color: 0xff0000 });
                const obstacle = new THREE.Mesh(obstacleGeometry, obstacleMaterial);
                obstacle.position.set(
                    (Math.random() - 0.5) * 3,
                    0.5,
                    zPosition + (Math.random() - 0.5) * 8
                );
                scene.add(obstacle);
                obstacles.push(obstacle);

                if (Math.random() > 0.7) {
                    const yellowGeometry = new THREE.BoxGeometry(1, 1, 1);
                    const yellowMaterial = new THREE.MeshPhongMaterial({ color: 0xffff00 });
                    const yellowBlock = new THREE.Mesh(yellowGeometry, yellowMaterial);
                    yellowBlock.position.set(
                        (Math.random() - 0.5) * 3,
                        2,
                        zPosition + (Math.random() - 0.5) * 8
                    );
                    scene.add(yellowBlock);
                    yellowBlocks.push(yellowBlock);
                }

                if (Math.random() > 0.5) {
                    createBlueBlock(zPosition);
                }

                if (Math.random() > 0.6) {  
                    createOrangeBlock(zPosition);
                }

                if (Math.random() > 0.8) {  
                    createPurpleBlock(zPosition);
                }
            }
        }

        function createBlueBlock(zPosition) {
            const blueGeometry = new THREE.BoxGeometry(2, 0.5, 2);
            const blueMaterial = new THREE.MeshPhongMaterial({ color: 0x0000ff });
            const blueBlock = new THREE.Mesh(blueGeometry, blueMaterial);
            const randomY = Math.random() * 2 + 2; 
            blueBlock.position.set(
                (Math.random() - 0.5) * 3,
                randomY,
                zPosition + (Math.random() - 0.5) * 8
            );
            scene.add(blueBlock);
            blueBlocks.push(blueBlock);
        }

        function createOrangeBlock(zPosition) {
            const orangeGeometry = new THREE.BoxGeometry(2, 0.5, 2);
            const orangeMaterial = new THREE.MeshPhongMaterial({ color: 0xff8c00 });
            const orangeBlock = new THREE.Mesh(orangeGeometry, orangeMaterial);
            const randomY = Math.random() * 2 + 1.5; 
            orangeBlock.position.set(
                (Math.random() - 0.5) * 3,
                randomY,
                zPosition + (Math.random() - 0.5) * 8
            );
            scene.add(orangeBlock);
            orangeBlocks.push(orangeBlock);
        }

        function createPurpleBlock(zPosition) {
            const purpleGeometry = new THREE.BoxGeometry(1, 1, 1);
            const purpleMaterial = new THREE.MeshPhongMaterial({ color: 0x800080 });
            const purpleBlock = new THREE.Mesh(purpleGeometry, purpleMaterial);
            purpleBlock.position.set(
                (Math.random() - 0.5) * 3,
                2,
                zPosition + (Math.random() - 0.5) * 8
            );
            scene.add(purpleBlock);
            purpleBlocks.push(purpleBlock);
        }

        function onKeyDown(event) {
            if (isGameOver) {
                if (event.code === 'Enter') {
                    restartGame();
                }
                return;
            }
            
            switch(event.code) {
                case 'ArrowUp':  
                    if (jumpCount < maxJumps) {
                        playerVelocity = 0.3;
                        isJumping = true;
                        jumpCount++;
                    }
                    break;
                case 'ArrowLeft':
                    moveLeft = true;
                    break;
                case 'ArrowRight':
                    moveRight = true;
                    break;
            }
        }

        function onKeyUp(event) {
            switch(event.code) {
                case 'ArrowLeft':
                    moveLeft = false;
                    break;
                case 'ArrowRight':
                    moveRight = false;
                    break;
            }
        }

        function updateGame() {
            if (isGameOver) return;

            previewPlayer.position.copy(player.position);

            if (moveLeft && player.position.x > -(PLATFORM_WIDTH/2 - 0.5)) {
                player.position.x -= MOVEMENT_SPEED;
            }
            if (moveRight && player.position.x < (PLATFORM_WIDTH/2 - 0.5)) {
                player.position.x += MOVEMENT_SPEED;
            }

            player.scale.set(1, 1, 1);
            
            if (isJumping) {
                previewPlayer.scale.set(2, 2, 2);
            } else {
                previewPlayer.scale.set(1, 1, 1);
            }

            platforms.forEach((platform, index) => {
                platform.position.z += gameSpeed;
                if (platform.position.z > 20) {
                    scene.remove(platform);
                    platforms.splice(index, 1);
                    createPlatform(-80);
                }
            });

            obstacles.forEach((obstacle, index) => {
                obstacle.position.z += gameSpeed;
                if (obstacle.position.z > 20) {
                    scene.remove(obstacle);
                    obstacles.splice(index, 1);
                }
            });

            blueBlocks.forEach((block, index) => {
                block.position.z += gameSpeed;
                if (block.position.z > 20) {
                    scene.remove(block);
                    blueBlocks.splice(index, 1);
                }
            });

            yellowBlocks.forEach((block, index) => {
                block.position.z += gameSpeed;
                if (block.position.z > 20) {
                    scene.remove(block);
                    yellowBlocks.splice(index, 1);
                }
                if (checkCollision(player, block)) {
                    scene.remove(block);
                    yellowBlocks.splice(index, 1);
                    for (let i = 0; i < 3; i++) {
                        createBlueBlock(block.position.z - 20 - (i * 5));
                    }
                }
            });

            orangeBlocks.forEach((block, index) => {
                block.position.z += gameSpeed;
                if (block.position.z > 20) {
                    scene.remove(block);
                    orangeBlocks.splice(index, 1);
                }
                if (checkBlockCollision(player, block)) {
                    playerVelocity = 0.4; 
                    isJumping = true;
                }
            });

            purpleBlocks.forEach((block, index) => {
                block.position.z += gameSpeed;
                if (block.position.z > 20) {
                    scene.remove(block);
                    purpleBlocks.splice(index, 1);
                }
                if (checkCollision(player, block)) {
                    scene.remove(block);
                    purpleBlocks.splice(index, 1);
                    maxJumps = 4;  
                    remainingTime = 10;
                    document.getElementById('timer').style.display = 'block';
                    if (powerUpTimer) clearInterval(powerUpTimer);
                    powerUpTimer = setInterval(updateTimer, 1000);
                }
            });

            let isOnBlueBlock = false;
            blueBlocks.forEach(block => {
                if (checkBlockCollision(player, block)) {
                    isOnBlueBlock = true;
                    player.position.y = block.position.y + 0.75;
                    isJumping = false;
                    playerVelocity = 0;
                }
            });

            if (!isOnBlueBlock && !isJumping && player.position.y > 1) {
                isJumping = true;
                playerVelocity = 0;
            }

            if (isJumping) {
                player.position.y += playerVelocity;
                playerVelocity -= 0.01;

                if (player.position.y <= 1) {
                    player.position.y = 1;
                    isJumping = false;
                    playerVelocity = 0;
                }
            }

            if (!isJumping && player.position.y <= 1) {
                jumpCount = 0;
            }

            obstacles.forEach(obstacle => {
                if (checkCollision(player, obstacle)) {
                    gameOver();
                }
            });

            score += gameSpeed;
            document.getElementById('score').textContent = `Score: ${Math.floor(score)}`;
            
            gameSpeed += 0.0001;
        }

        function checkCollision(obj1, obj2) {
            const dx = obj1.position.x - obj2.position.x;
            const dy = obj1.position.y - obj2.position.y;
            const dz = obj1.position.z - obj2.position.z;
            const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
            return distance < 1.5;
        }

        function checkBlockCollision(player, block) {
            const dx = Math.abs(player.position.x - block.position.x);
            const dy = player.position.y - block.position.y;
            const dz = Math.abs(player.position.z - block.position.z);
            
            return dx < 1.5 && dy < 1 && dy > 0 && dz < 1.5 && player.position.y > block.position.y;
        }

        function gameOver() {
            isGameOver = true;
            document.getElementById('gameOver').style.display = 'block';
        }

        function updateTimer() {
            const timerElement = document.getElementById('timer');
            remainingTime--;
            if (remainingTime >= 0) {
                timerElement.textContent = `Quadruple Jump: ${remainingTime}s`;
            } else {
                timerElement.style.display = 'none';
                maxJumps = 1;
                clearInterval(powerUpTimer);
            }
        }

        function restartGame() {
            if (powerUpTimer) {
                clearInterval(powerUpTimer);
            }
            yellowBlocks.forEach(block => scene.remove(block));
            yellowBlocks = [];
            blueBlocks.forEach(block => scene.remove(block));
            blueBlocks = [];
            orangeBlocks.forEach(block => scene.remove(block)); 
            orangeBlocks = [];
            purpleBlocks.forEach(block => scene.remove(block));
            purpleBlocks = [];
            scene.remove(previewPlayer);
            maxJumps = 1;
            jumpCount = 0;
            location.reload();
        }

        function animate() {
            requestAnimationFrame(animate);
            updateGame();
            renderer.render(scene, camera);
            
            // Render preview
            previewRenderer.render(scene, previewCamera);
        }

        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
            
            const aspect = 200 / 150;
            previewCamera.left = -5;
            previewCamera.right = 5;
            previewCamera.top = 5 / aspect;
            previewCamera.bottom = -5 / aspect;
            previewCamera.updateProjectionMatrix();
            previewRenderer.setSize(200, 150);
        });

        window.restartGame = restartGame;
        init();
    </script>
</body>
</html>