• 01 - Critter Models 02
  • 02 - VantaJS Shaders
  • 03 - App Bundle 02
  • 04 - Cathedrals
  • 05 - App Bundle 01
  • 06 - Retroscopic
  • 07 - Games
  • 08 - Voronoi
  • 09 - Terrain
  • 10 - Critter Models 01
  • 11 - Chromatophores
  • 12 - Conformal Maps
  • 13 - Echo Logix
  • 14 - Music
  • 15 - Colour Theory
MIKE'S NOTEBOOK
Notes
Number:
Project:
07Games
└ Rockfall└ Speak & Math└ Space Invaders└ Apache└ Asteroids└ Molly Roger└ Carrom└ Chess└ Connect 4└ Anagrams
08Voronoi
└ 001└ 002└ 003└ 004└ 005
09Terrain
└ Simple Polygon└ Simple Flyover└ Infinite Flyover 01└ Infinite Flyover 02└ Hexagonal Plane└ Mountain Ridges
10Critter Models 01
└ Wireframe Spider└ Wireframe Fly└ Wireframe Scorpion└ Wireframe Mosquito└ Wireframe Bee└ Wireframe Butterfly└ Wireframe Locust
11Chromatophores
└ 01└ 02└ 03└ 04
12Conformal Maps
└ 01└ 02└ 03└ 04└ 05
02 / 03

SIMPLE POLYGON - 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>Colorful Terrain Animation</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/r71/three.min.js"></script>
    <script>
        var container = document.getElementById('container')

        var vertexHeight = 15000,
            planeDefinition = 100,
            planeSize = 1245000,
            totalObjects = 1,
            background = "#001a33",
            meshColor = "#ff6b6b";

        var camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 1, 400000)
        camera.position.z = 10000;
        camera.position.y = 10000;
        var scene = new THREE.Scene();
        scene.fog = new THREE.Fog(background, 1, 300000);
        var light = new THREE.AmbientLight(0x404040);
        scene.add(light);
        var directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(0, 1, 0);
        scene.add(directionalLight);
        var planeGeo = new THREE.PlaneGeometry(planeSize, planeSize, planeDefinition, planeDefinition);
        var plane = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({
            color: meshColor,
            wireframe: true
        }));
        plane.rotation.x -= Math.PI * .5;
        scene.add(plane);
        var renderer = new THREE.WebGLRenderer({alpha: false});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(background, 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("#f0f4f8", 1);
                        scene.fog.color.setStyle("#f0f4f8");
                    }
                } else {
                    document.body.style.backgroundColor = '#000';
                    if (typeof renderer !== 'undefined' && typeof scene !== 'undefined') {
                        renderer.setClearColor("#001a33", 1);
                        scene.fog.color.setStyle("#001a33");
                    }
                }
            } 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);

        updatePlane();
        function updatePlane() {
            for (var i = 0; i < planeGeo.vertices.length; i++) {
                planeGeo.vertices[i].z += Math.random() * vertexHeight - vertexHeight;
                planeGeo.vertices[i]._myZ = planeGeo.vertices[i].z
            }
        };
        var count = 0
        function render() {
            requestAnimationFrame(render);
            var x = camera.position.x;
            var z = camera.position.z;
            camera.position.x = x * Math.cos(0.001) + z * Math.sin(0.001) - 10;
            camera.position.z = z * Math.cos(0.001) - x * Math.sin(0.001) - 10;
            camera.lookAt(new THREE.Vector3(0, 8000, 0))
            for (var i = 0; i < planeGeo.vertices.length; i++) {
                var z = +planeGeo.vertices[i].z;
                planeGeo.vertices[i].z = Math.sin(( i + count * 0.00002)) * (planeGeo.vertices[i]._myZ - (planeGeo.vertices[i]._myZ* 0.6))
                planeGeo.verticesNeedUpdate = true;
            }

            var hue = (count * 0.0001) % 1;
            plane.material.color.setHSL(hue, 0.8, 0.5);
            var angle = count * 0.01;
            directionalLight.position.x = Math.cos(angle) * 10000;
            directionalLight.position.z = Math.sin(angle) * 10000;
            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);
        }
    </script>
</body>
</html>
MikeHiggins.me.uk LinkedIn GitHub Bluesky Contra Upwork
© 2026 Mike Higgins. All rights reserved.