Meta Description" name="description" />

Share this result

Previews are deleted daily. Get a permanent share link sent to your inbox:
Script
<!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>3D Battle Royale</title> <style> * { box-sizing: border-box; user-select: none; -webkit-user-select: none; } body { margin: 0; overflow: hidden; background: #000; font-family: Arial, sans-serif; touch-action: none; } #game { width: 100vw; height: 100vh; } #hud { position: fixed; top: 15px; left: 15px; color: white; z-index: 10; font-size: 18px; text-shadow: 2px 2px 4px black; } #healthBox { width: 180px; height: 20px; background: #333; border: 2px solid white; border-radius: 10px; overflow: hidden; margin-top: 5px; } #health { width: 100%; height: 100%; background: #20e020; } #crosshair { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); color: white; font-size: 30px; z-index: 5; text-shadow: 0 0 5px black; } #message { display: none; position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); color: white; text-align: center; z-index: 50; font-size: 35px; font-weight: bold; } #message button { padding: 12px 25px; font-size: 18px; margin-top: 20px; border: 0; border-radius: 10px; } #mobileControls { position: fixed; inset: 0; pointer-events: none; z-index: 20; } .control { pointer-events: auto; position: absolute; width: 65px; height: 65px; border-radius: 50%; border: 2px solid rgba(255,255,255,.7); background: rgba(0,0,0,.4); color: white; font-size: 25px; display: flex; justify-content: center; align-items: center; } #left { left: 25px; bottom: 75px; } #right { left: 170px; bottom: 75px; } #forward { left: 98px; bottom: 145px; } #back { left: 98px; bottom: 5px; } #shoot { right: 30px; bottom: 80px; width: 90px; height: 90px; background: rgba(200,0,0,.65); } #aim { right: 135px; bottom: 35px; } #run { right: 30px; bottom: 190px; } @media (min-width: 900px) { #mobileControls { display: none; } } </style> </head> <body> <div id="game"></div> <div id="hud"> ❀️ HP <div id="healthBox"> <div id="health"></div> </div> πŸ”« Ammo: <span id="ammo">30</span><br> 🎯 Kills: <span id="kills">0</span><br> πŸ† Score: <span id="score">0</span> </div> <div id="crosshair">+</div> <div id="message"> <div id="messageText">GAME OVER</div> <button onclick="location.reload()">PLAY AGAIN</button> </div> <div id="mobileControls"> <div class="control" id="forward">β–²</div> <div class="control" id="left">β—€</div> <div class="control" id="right">β–Ά</div> <div class="control" id="back">β–Ό</div> <div class="control" id="aim">🎯</div> <div class="control" id="shoot">πŸ”«</div> <div class="control" id="run">πŸƒ</div> </div> <script type="importmap"> { "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js" } } </script> <script type="module"> import * as THREE from "three"; /* ========================= BASIC SETUP ========================= */ const scene = new THREE.Scene(); scene.background = new THREE.Color(0x87ceeb); scene.fog = new THREE.Fog(0x87ceeb, 40, 180); const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 500 ); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setPixelRatio( Math.min(window.devicePixelRatio, 2) ); renderer.shadowMap.enabled = true; document.getElementById("game").appendChild(renderer.domElement); /* ========================= LIGHT ========================= */ const sunlight = new THREE.DirectionalLight( 0xffffff, 2 ); sunlight.position.set(50, 100, 30); sunlight.castShadow = true; scene.add(sunlight); scene.add( new THREE.HemisphereLight( 0xffffff, 0x444444, 1.2 ) ); /* ========================= GROUND ========================= */ const groundGeometry = new THREE.PlaneGeometry(300, 300); const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x3d8b3d }); const ground = new THREE.Mesh( groundGeometry, groundMaterial ); ground.rotation.x = -Math.PI / 2; ground.receiveShadow = true; scene.add(ground); /* ========================= WATER ========================= */ const waterGeometry = new THREE.PlaneGeometry(500, 500); const waterMaterial = new THREE.MeshStandardMaterial({ color: 0x2080c0, transparent: true, opacity: .8 }); const water = new THREE.Mesh( waterGeometry, waterMaterial ); water.rotation.x = -Math.PI / 2; water.position.y = -0.2; scene.add(water); /* ========================= PLAYER ========================= */ const player = new THREE.Group(); scene.add(player); player.position.set( 0, 1, 20 ); /* BODY */ const body = new THREE.Mesh( new THREE.BoxGeometry( 1, 1.5, .6 ), new THREE.MeshStandardMaterial({ color: 0x2255ff }) ); body.position.y = 1; body.castShadow = true; player.add(body); /* HEAD */ const head = new THREE.Mesh( new THREE.SphereGeometry( .38, 16, 16 ), new THREE.MeshStandardMaterial({ color: 0xffc49b }) ); head.position.y = 2; head.castShadow = true; player.add(head); /* GUN */ const gun = new THREE.Mesh( new THREE.BoxGeometry( .2, .2, 1.5 ), new THREE.MeshStandardMaterial({ color: 0x222222 }) ); gun.position.set( .55, 1.25, -.8 ); player.add(gun); /* ========================= ENEMIES ========================= */ let enemies = []; let kills = 0; let score = 0; function createEnemy() { const enemy = new THREE.Group(); enemy.position.set( (Math.random() - .5) * 120, 0, (Math.random() - .5) * 120 ); const enemyBody = new THREE.Mesh( new THREE.BoxGeometry( 1, 1.5, .6 ), new THREE.MeshStandardMaterial({ color: 0xff2222 }) ); enemyBody.position.y = 1; enemyBody.castShadow = true; enemy.add(enemyBody); const enemyHead = new THREE.Mesh( new THREE.SphereGeometry( .38, 16, 16 ), new THREE.MeshStandardMaterial({ color: 0xffc49b }) ); enemyHead.position.y = 2; enemy.add(enemyHead); enemy.userData.health = 100; scene.add(enemy); enemies.push(enemy); } for (let i = 0; i < 12; i++) { createEnemy(); } /* ========================= TREES ========================= */ function createTree(x, z) { const tree = new THREE.Group(); const trunk = new THREE.Mesh( new THREE.CylinderGeometry( .25, .35, 3 ), new THREE.MeshStandardMaterial({ color: 0x75451f }) ); trunk.position.y = 1.5; tree.add(trunk); const leaves = new THREE.Mesh( new THREE.SphereGeometry( 1.5, 12, 12 ), new THREE.MeshStandardMaterial({ color: 0x08752c }) ); leaves.position.y = 3.5; tree.add(leaves); tree.position.set(x, 0, z); scene.add(tree); } for (let i = 0; i < 80; i++) { createTree( (Math.random() - .5) * 250, (Math.random() - .5) * 250 ); } /* ========================= BUILDINGS ========================= */ function createBuilding(x, z) { const building = new THREE.Mesh( new THREE.BoxGeometry( 5, 8 + Math.random() * 8, 5 ), new THREE.MeshStandardMaterial({ color: new THREE.Color( Math.random(), Math.random(), Math.random() ) }) ); building.position.set( x, building.geometry.parameters.height / 2, z ); building.castShadow = true; scene.add(building); } for (let i = 0; i < 20; i++) { createBuilding( (Math.random() - .5) * 150, (Math.random() - .5) * 150 ); } /* ========================= BULLETS ========================= */ let bullets = []; let ammo = 30; function shoot() { if (ammo <= 0) return; ammo--; document.getElementById( "ammo" ).textContent = ammo; const bullet = new THREE.Mesh( new THREE.SphereGeometry( .08, 8, 8 ), new THREE.MeshBasicMaterial({ color: 0xffff00 }) ); bullet.position.copy( player.position ); bullet.position.y += 1.4; const direction = new THREE.Vector3(); camera.getWorldDirection( direction ); bullet.userData.velocity = direction.multiplyScalar(2); scene.add(bullet); bullets.push(bullet); } /* ========================= PLAYER HEALTH ========================= */ let health = 100; function damagePlayer(amount) { health -= amount; if (health < 0) health = 0; document.getElementById( "health" ).style.width = health + "%"; if (health <= 0) { document.getElementById( "message" ).style.display = "block"; document.getElementById( "messageText" ).textContent = "πŸ’€ YOU DIED"; gameOver = true; } } /* ========================= KEYBOARD ========================= */ const keys = {}; document.addEventListener( "keydown", e => { keys[e.key.toLowerCase()] = true; if (e.key === " ") shoot(); } ); document.addEventListener( "keyup", e => { keys[e.key.toLowerCase()] = false; } ); /* ========================= MOBILE CONTROLS ========================= */ function mobileButton( id, key ) { const button = document.getElementById(id); button.addEventListener( "touchstart", e => { e.preventDefault(); keys[key] = true; } ); button.addEventListener( "touchend", e => { e.preventDefault(); keys[key] = false; } ); } mobileButton( "forward", "w" ); mobileButton( "back", "s" ); mobileButton( "left", "a" ); mobileButton( "right", "d" ); document.getElementById( "shoot" ).addEventListener( "touchstart", e => { e.preventDefault(); shoot(); } ); /* ========================= PLAYER MOVEMENT ========================= */ let gameOver = false; const clock = new THREE.Clock(); function updatePlayer(delta) { if (gameOver) return; let speed = 7; if (keys["shift"]) speed = 13; if (keys["w"]) player.translateZ( -speed * delta ); if (keys["s"]) player.translateZ( speed * delta ); if (keys["a"]) player.rotation.y += 2.5 * delta; if (keys["d"]) player.rotation.y -= 2.5 * delta; /* keep player inside island */ player.position.x = THREE.MathUtils.clamp( player.position.x, -140, 140 ); player.position.z = THREE.MathUtils.clamp( player.position.z, -140, 140 ); } /* ========================= ENEMY AI ========================= */ function updateEnemies(delta) { enemies.forEach( enemy => { if (!enemy) return; const distance = enemy.position.distanceTo( player.position ); if (distance < 45) { enemy.lookAt( player.position.x, 0, player.position.z ); if (distance > 5) { enemy.translateZ( -2 * delta ); } else { damagePlayer( 5 * delta ); } } } ); } /* ========================= BULLET SYSTEM ========================= */ function updateBullets(delta) { bullets.forEach( (bullet, bIndex) => { bullet.position.add( bullet.userData.velocity .clone() .multiplyScalar( delta * 60 ) ); enemies.forEach( (enemy, eIndex) => { if ( bullet.position.distanceTo( enemy.position ) < 1.5 ) { enemy.userData.health -= 50; scene.remove(bullet); bullets.splice( bIndex, 1 ); if ( enemy.userData.health <= 0 ) { scene.remove(enemy); enemies.splice( eIndex, 1 ); kills++; score += 100; document.getElementById( "kills" ).textContent = kills; document.getElementById( "score" ).textContent = score; setTimeout( createEnemy, 1500 ); } } } ); if ( bullet.position.length() > 250 ) { scene.remove(bullet); } } ); } /* ========================= THIRD PERSON CAMERA ========================= */ function updateCamera() { const cameraOffset = new THREE.Vector3( 0, 5, 8 ); cameraOffset.applyQuaternion( player.quaternion ); const target = player.position .clone() .add(cameraOffset); camera.position.lerp( target, .12 ); camera.lookAt( player.position.x, player.position.y + 1, player.position.z ); } /* ========================= GAME LOOP ========================= */ function animate() { requestAnimationFrame( animate ); const delta = Math.min( clock.getDelta(), .05 ); updatePlayer(delta); updateEnemies(delta); updateBullets(delta); updateCamera(); renderer.render( scene, camera ); } animate(); /* ========================= RESIZE ========================= */ window.addEventListener( "resize", () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } ); </script> </body> </html>
Landing Page
This ad does not have a landing page available
Network Timeline
Performance Summary

3

Requests

2

Domains

385KB

Transfer Size

1977KB

Content Size

497.0ms

Dom Content Loaded

200.0ms

First Paint

498.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...