Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Voxel Sandbox Mobile</title> <style> body { margin:0; overflow:hidden; background:black; } #ui { position: fixed; bottom: 10px; width: 100%; text-align: center; color: white; font-family: sans-serif; } #crosshair { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 20px; color: white; } </style> </head> <body> <div id="crosshair">+</div> <div id="ui">Block: <span id="block">Grass</span></div> <script src="https://cdn.jsdelivr.net/npm/three@0.158/build/three.min.js"></script> <script> // ===== SETUP ===== const scene = new THREE.Scene(); scene.background = new THREE.Color(0x87CEEB); const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); // LIGHT const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(50,100,50); scene.add(light); // ===== BLOCK TYPES ===== const BLOCK = { GRASS: 0, DIRT: 1, STONE: 2 }; const materials = [ new THREE.MeshLambertMaterial({color: 0x00aa00}), new THREE.MeshLambertMaterial({color: 0x8B4513}), new THREE.MeshLambertMaterial({color: 0x888888}) ]; // ===== WORLD ===== const world = {}; const size = 32; const height = 16; function noise(x,z){ return Math.floor((Math.sin(x*0.2)+Math.cos(z*0.2))*2 + 6); } // generate terrain for(let x=0;x<size;x++){ for(let z=0;z<size;z++){ let h = noise(x,z); for(let y=0;y<h;y++){ let type = BLOCK.STONE; if(y > h-2) type = BLOCK.GRASS; else if(y > h-4) type = BLOCK.DIRT; world[`${x},${y},${z}`] = type; } } } // ===== MESH ===== const meshes = {}; function createBlock(x,y,z,type){ const geo = new THREE.BoxGeometry(1,1,1); const mesh = new THREE.Mesh(geo, materials[type]); mesh.position.set(x,y,z); scene.add(mesh); meshes[`${x},${y},${z}`] = mesh; } // render visible blocks only for(let key in world){ let [x,y,z] = key.split(',').map(Number); let neighbors = [ `${x+1},${y},${z}`, `${x-1},${y},${z}`, `${x},${y+1},${z}`, `${x},${y-1},${z}`, `${x},${y},${z+1}`, `${x},${y},${z-1}` ]; let visible = neighbors.some(n => !world[n]); if(visible){ createBlock(x,y,z,world[key]); } } // ===== PLAYER ===== camera.position.set(10,10,10); let velocity = new THREE.Vector3(); let keys = {}; window.addEventListener('keydown', e => keys[e.key]=true); window.addEventListener('keyup', e => keys[e.key]=false); // TOUCH LOOK let touchX=0, touchY=0; window.addEventListener('touchmove', e=>{ let t = e.touches[0]; touchX = (t.clientX/window.innerWidth - 0.5)*2; touchY = (t.clientY/window.innerHeight - 0.5)*2; }); // ===== RAYCAST ===== const raycaster = new THREE.Raycaster(); function interact(place=false){ raycaster.setFromCamera({x:0,y:0}, camera); const intersects = raycaster.intersectObjects(Object.values(meshes)); if(intersects.length > 0){ const obj = intersects[0].object; const pos = obj.position; if(place){ let nx = Math.round(pos.x + intersects[0].face.normal.x); let ny = Math.round(pos.y + intersects[0].face.normal.y); let nz = Math.round(pos.z + intersects[0].face.normal.z); if(!world[`${nx},${ny},${nz}`]){ world[`${nx},${ny},${nz}`] = selectedBlock; createBlock(nx,ny,nz,selectedBlock); } } else { scene.remove(obj); delete meshes[`${pos.x},${pos.y},${pos.z}`]; delete world[`${pos.x},${pos.y},${pos.z}`]; } } } // tap = break, double tap = place let lastTap = 0; window.addEventListener('touchstart', ()=>{ let now = Date.now(); if(now - lastTap < 300){ interact(true); } else { interact(false); } lastTap = now; }); // ===== HOTBAR ===== let selectedBlock = 0; const names = ["Grass","Dirt","Stone"]; window.addEventListener('wheel', e=>{ selectedBlock = (selectedBlock + (e.deltaY>0?1:-1) + 3)%3; document.getElementById("block").innerText = names[selectedBlock]; }); // ===== LOOP ===== function animate(){ requestAnimationFrame(animate); // movement let speed = 0.1; if(keys['w']) camera.position.z -= speed; if(keys['s']) camera.position.z += speed; if(keys['a']) camera.position.x -= speed; if(keys['d']) camera.position.x += speed; // look camera.rotation.y = -touchX; camera.rotation.x = -touchY; renderer.render(scene, camera); } animate(); </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

2

Requests

2

Domains

164KB

Transfer Size

641KB

Content Size

1,784.0ms

Dom Content Loaded

112.0ms

First Paint

1,784.0ms

Load Time
Domain Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...
Timings (ms)
Loading...
Total Time
Loading...
Content Breakdown
Transfer Size (bytes)
Loading...
Content Size (bytes)
Loading...
Header Size (bytes)
Loading...
Requests
Loading...