<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vectaria.RI</title>
    <style>
        body { margin: 0; overflow: hidden; background: #87CEEB; font-family: sans-serif; }
        canvas { display: block; }
        #crosshair { position: absolute; top: 50%; left: 50%; width: 10px; height: 10px; background: white; transform: translate(-50%, -50%); border-radius: 50%; pointer-events: none; mix-blend-mode: difference; }
        #menu { position: absolute; width: 100%; height: 100%; background: rgba(0,0,0,0.7); color: white; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; cursor: pointer; z-index: 10; }
    </style>
</head>
<body>
    <div id="crosshair"></div>
    <div id="menu">
        <h1 style="margin-bottom:10px;">Vectaria.RI</h1>
        <h3 style="margin-top:0; color:#4CAF50;">CLICK TO PLAY</h3>
        <p>W, A, S, D = Move | Space = Jump</p>
        <p>Left Click = Destroy | Right Click = Build</p>
    </div>

    <script type="module">
        import * as THREE from 'https://jsdelivr.net';
        import { PointerLockControls } from 'https://jsdelivr.net';

        // 1. Core Setup
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x87CEEB);
        scene.fog = new THREE.FogExp2(0x87CEEB, 0.03);

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

        // Lights
        scene.add(new THREE.AmbientLight(0xffffff, 0.6));
        const sun = new THREE.DirectionalLight(0xffffff, 0.8);
        sun.position.set(20, 40, 20);
        scene.add(sun);

        // Controls
        const controls = new PointerLockControls(camera, document.body);
        const menu = document.getElementById('menu');
        menu.addEventListener('click', () => controls.lock());
        controls.addEventListener('lock', () => menu.style.display = 'none');
        controls.addEventListener('unlock', () => menu.style.display = 'flex');
        scene.add(controls.getObject());

        // 2. Physics & State Variables
        const keys = { w:0, a:0, s:0, d:0, space: false };
        let velocity = new THREE.Vector3(), direction = new THREE.Vector3();
        let prevTime = performance.now();
        camera.position.set(5, 3, 5);

        // Canvas Procedural Gritty Texture
        function createBlockTexture(colorHex) {
            const canvas = document.createElement('canvas');
            canvas.width = 16; canvas.height = 16;
            const ctx = canvas.getContext('2d');
            ctx.fillStyle = colorHex; ctx.fillRect(0, 0, 16, 16);
            for(let i=0; i<32; i++) {
                ctx.fillStyle = Math.random() > 0.5 ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)';
                ctx.fillRect(Math.floor(Math.random()*16), Math.floor(Math.random()*16), 1, 1);
            }
            const texture = new THREE.CanvasTexture(canvas);
            texture.magFilter = THREE.NearestFilter;
            return texture;
        }

        const blockMat = new THREE.MeshLambertMaterial({ map: createBlockTexture('#55aa55') });
        const blockGeo = new THREE.BoxGeometry(1, 1, 1);
        const blocksArray = [];

        // 3. Generate Map Ground
        for (let x = 0; x < 16; x++) {
            for (let z = 0; z < 16; z++) {
                const mesh = new THREE.Mesh(blockGeo, blockMat);
                mesh.position.set(x, 0, z);
                scene.add(mesh);
                blocksArray.push(mesh);
            }
        }

        // Input Listeners
        document.addEventListener('keydown', (e) => {
            if(e.code==='KeyW') keys.w=1; if(e.code==='KeyS') keys.s=1;
            if(e.code==='KeyA') keys.a=1; if(e.code==='KeyD') keys.d=1;
            if(e.code==='Space') keys.space=true;
        });
        document.addEventListener('keyup', (e) => {
            if(e.code==='KeyW') keys.w=0; if(e.code==='KeyS') keys.s=0;
            if(e.code==='KeyA') keys.a=0; if(e.code==='KeyD') keys.d=0;
            if(e.code==='Space') keys.space=false;
        });

        // 4. Click Actions: Build & Destroy
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2(0, 0);

        window.addEventListener('pointerdown', (e) => {
            if (!controls.isLocked) return;
            raycaster.setFromCamera(mouse, camera);
            const intersects = raycaster.intersectObjects(blocksArray);

            if (intersects.length > 0 && intersects.distance < 6) {
                const hit = intersects[0];
                
                if (e.button === 0) { // Left-click: Break
                    scene.remove(hit.object);
                    const index = blocksArray.indexOf(hit.object);
                    if (index > -1) blocksArray.splice(index, 1);
                } 
                else if (e.button === 2) { // Right-click: Place
                    const normal = hit.face.normal;
                    const newBlock = new THREE.Mesh(blockGeo, blockMat);
                    newBlock.position.copy(hit.object.position).add(normal);
                    scene.add(newBlock);
                    blocksArray.push(newBlock);
                }
            }
        });
        window.addEventListener('contextmenu', e => e.preventDefault());

        // 5. Physics Animation Loop
        function animate() {
            requestAnimationFrame(animate);
            if (controls.isLocked) {
                const time = performance.now(), delta = (time - prevTime) / 1000;

                velocity.x -= velocity.x * 10.0 * delta;
                velocity.z -= velocity.z * 10.0 * delta;
                velocity.y -= 9.8 * 2.5 * delta;

                direction.z = keys.w - keys.s;
                direction.x = keys.d - keys.a;
                direction.normalize();

                if (keys.w || keys.s) velocity.z -= direction.z * 45.0 * delta;
                if (keys.a || keys.d) velocity.x -= direction.x * 45.0 * delta;

                controls.moveRight(-velocity.x * delta);
                controls.moveForward(-velocity.z * delta);
                controls.getObject().position.y += velocity.y * delta;

                if (controls.getObject().position.y < 2) {
                    velocity.y = 0;
                    controls.getObject().position.y = 2;
                    if (keys.space) velocity.y = 8;
                }
                prevTime = time;
            }
            renderer.render(scene, camera);
        }
        animate();

        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    </script>
</body>
</html>
