SIMPLE FLYOVER - TERRAIN ANIMATION SOURCE CODE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Retro Wireframe Flyover</title>
<style>
html, body {
border: 0;
padding: 0;
margin: 0;
overflow: hidden;
height: 100%;
width: 100%;
background: #000;
}
#container {
height: 100vh;
width: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
try {
var container = document.getElementById('container');
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.set(0, 5000, 0);
camera.rotation.x = -Math.PI / 3;
var scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x1a0033, 10000, 40000);
// Create foreground plane
var planeSize = 30000;
var segments = 20;
var planeGeo = new THREE.PlaneGeometry(planeSize, planeSize, segments, segments);
var planeFront = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({
color: 0xff00ff,
wireframe: true
}));
planeFront.rotation.x = -Math.PI / 2;
planeFront.position.z = 0;
scene.add(planeFront);
// Create background plane
var planeGeo2 = new THREE.PlaneGeometry(planeSize, planeSize, segments, segments);
var planeBack = new THREE.Mesh(planeGeo2, new THREE.MeshBasicMaterial({
color: 0x00ffff,
wireframe: true,
transparent: true,
opacity: 0.5
}));
planeBack.rotation.x = -Math.PI / 2;
planeBack.position.z = planeSize;
scene.add(planeBack);
var renderer = new THREE.WebGLRenderer({alpha: false, antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x0a0015, 1);
container.appendChild(renderer.domElement);
// ---------- THEME SYNC ----------
function syncTheme() {
try {
var isDark = true;
if (window.parent && window.parent.document) {
isDark = window.parent.document.documentElement.classList.contains('dark');
} else {
var theme = localStorage.getItem('theme');
isDark = theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches);
}
if (!isDark) {
document.body.style.backgroundColor = '#f0f4f8';
if (typeof renderer !== 'undefined' && typeof scene !== 'undefined') {
renderer.setClearColor(0xf0f4f8, 1);
scene.fog.color.setHex(0xf0f4f8);
}
} else {
document.body.style.backgroundColor = '#0a0015';
if (typeof renderer !== 'undefined' && typeof scene !== 'undefined') {
renderer.setClearColor(0x0a0015, 1);
scene.fog.color.setHex(0x1a0033);
}
}
} catch (e) {
console.warn("Could not sync theme", e);
}
}
syncTheme();
if (window.parent && window.parent.document) {
try {
var observer = new MutationObserver(syncTheme);
observer.observe(window.parent.document.documentElement, { attributes: true, attributeFilter: ['class'] });
} catch(e) {}
}
window.addEventListener('storage', syncTheme);
var count = 0;
var speed = 50;
function render() {
requestAnimationFrame(render);
// Move planes forward
planeFront.position.z -= speed;
planeBack.position.z -= speed;
// Loop planes seamlessly
if (planeFront.position.z < -planeSize) {
planeFront.position.z = planeSize;
}
if (planeBack.position.z < -planeSize) {
planeBack.position.z = planeSize;
}
// Animate vertices
var positions = planeFront.geometry.attributes.position;
for (var i = 0; i < positions.count; i++) {
var x = positions.getX(i);
var y = positions.getY(i);
var wave = Math.sin(x * 0.0005 + y * 0.0005 + count * 0.05) * 2000;
positions.setZ(i, wave);
}
positions.needsUpdate = true;
var positions2 = planeBack.geometry.attributes.position;
for (var i = 0; i < positions2.count; i++) {
var x = positions2.getX(i);
var y = positions2.getY(i);
var wave = Math.sin(x * 0.0005 + y * 0.0005 + count * 0.05) * 2000;
positions2.setZ(i, wave);
}
positions2.needsUpdate = true;
count += 0.1;
renderer.render(scene, camera);
}
render();
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
} catch(e) {
console.error('Error:', e);
document.body.innerHTML = '<div style="color:white;padding:20px;">Error loading animation: ' + e.message + '</div>';
}
</script>
</body>
</html>