<title>Neon Survival FPS</title>
<style>
body { margin:0; overflow:hidden; background: #000; font-family: monospace; }
#ui { position: fixed; top: 20px; left: 20px; color: #0f0; font-size: 20px; pointer-events: none; }
#crosshair {
position:fixed; top:50%; left:50%; width:10px; height:10px;
border: 2px solid #0f0; border-radius:50%; transform:translate(-50%,-50%);
pointer-events:none;
}
#msg {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
color: white; background: rgba(0,0,0,0.8); padding: 20px; text-align: center;
border: 1px solid #0f0; cursor: pointer;
}
</style>
SCORE: 0 | HEALTH: 100
NEON SURVIVAL
CLICK TO START
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.158/build/three.module.js";
import { PointerLockControls } from "https://cdn.jsdelivr.net/npm/three@0.158/examples/jsm/controls/PointerLockControls.js";
// --- SETUP ---
const scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x000000, 0, 100);
const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias:true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
// --- LIGHTING ---
const ambient = new THREE.AmbientLight(0x404040, 2);
scene.add(ambient);
const flash = new THREE.PointLight(0x00ff00, 0, 15);
scene.add(flash);
// --- STATE ---
let score = 0, health = 100, active = false;
const enemies = [], move = { w:false, s:false, a:false, d:false };
// --- CONTROLS ---
const controls = new PointerLockControls(camera, document.body);
const msg = document.getElementById('msg');
msg.addEventListener('click', () => { if(health > 0) controls.lock(); else location.reload(); });
controls.addEventListener('lock', () => { msg.style.display = 'none'; active = true; });
controls.addEventListener('unlock', () => { msg.style.display = 'block'; active = false; });
// --- OBJECTS ---
const grid = new THREE.GridHelper(200, 40, 0x00ff00, 0x222222);
scene.add(grid);
const gun = new THREE.Mesh(
new THREE.BoxGeometry(0.2, 0.2, 0.8),
new THREE.MeshStandardMaterial({ color: 0x222222 })
);
gun.position.set(0.4, -0.4, -0.6);
camera.add(gun);
scene.add(controls.getObject());
function spawnEnemy() {
const obj = new THREE.Mesh(
new THREE.BoxGeometry(1.5, 1.5, 1.5),
new THREE.MeshStandardMaterial({ color: 0xff0000, emissive: 0xff0000, emissiveIntensity: 0.5 })
);
const angle = Math.random() * Math.PI * 2;
obj.position.set(Math.cos(angle)*50, 1, Math.sin(angle)*50);
scene.add(obj);
enemies.push(obj);
}
for(let i=0; i<6; i++) spawnEnemy();
// --- LOGIC ---
const raycaster = new THREE.Raycaster();
document.addEventListener('mousedown', () => {
if(!controls.isLocked) return;
flash.intensity = 20;
flash.position.copy(camera.position);
gun.position.z = -0.4;
raycaster.setFromCamera(new THREE.Vector2(0,0), camera);
const hits = raycaster.intersectObjects(enemies);
if(hits.length > 0) {
scene.remove(hits[0].object);
enemies.splice(enemies.indexOf(hits[0].object), 1);
score += 10;
updateUI();
spawnEnemy();
}
});
function updateUI() {
document.getElementById('ui').innerText = `SCORE: ${score} | HEALTH: ${health}`;
}
document.addEventListener('keydown', e => move[e.key.toLowerCase()] = true);
document.addEventListener('keyup', e => move[e.key.toLowerCase()] = false);
// --- LOOP ---
function animate() {
requestAnimationFrame(animate);
if(!active) return;
const speed = 0.15;
if(move.w) controls.moveForward(speed);
if(move.s) controls.moveForward(-speed);
if(move.a) controls.moveRight(-speed);
if(move.d) controls.moveRight(speed);
gun.position.z += (-0.6 - gun.position.z) * 0.1;
flash.intensity *= 0.8;
enemies.forEach(en => {
const dir = new THREE.Vector3().subVectors(camera.position, en.position).normalize();
en.position.add(dir.multiplyScalar(0.06));
if(en.position.distanceTo(camera.position) < 2.5) {
health -= 1;
updateUI();
if(health <= 0) {
active = false;
controls.unlock();
msg.innerHTML = "
GAME OVER
CLICK TO RESTART
";
}
}
});
renderer.render(scene, camera);
}
animate();
</script>
NEON SURVIVAL
CLICK TO START
GAME OVER
CLICK TO RESTART
"; } } }); renderer.render(scene, camera); } animate(); </script>