• 01 - CSS: Insects
  • 02 - Critter Models 02
  • 03 - VantaJS Shaders
  • 04 - App Bundle 02
  • 05 - Cathedrals
  • 06 - Board Games
  • 07 - App Bundle 01
  • 08 - Retroscopic
  • 09 - Games 26
  • 10 - Voronoi
  • 11 - Terrain
  • 12 - Critter Models 01
  • 13 - Chromatophores
  • 14 - Conformal Maps
  • 15 - Echo Logix
  • 16 - Music 26
  • 17 - Colour Theory
ARCHIVE
Notes
Number:
Project:
08Retroscopic
└ Galaxy└ Ocean└ Slime└ 24-Cell└ Unicorn└ Polyp└ Oneiric 1└ Oneiric 2└ Node└ Torus Knot└ GLSL Grid└ Liquid Crystal└ Silky└ Butterfly└ Ocean 2└ Icosahedron└ Luma└ Swarm└ Broken Solid└ Hypersphere└ Constraints└ Psycho Killer
09Games 26
└ Rockfall└ Speak & Math└ Space Invaders└ Apache└ Asteroids└ Molly Roger└ Anagrams
10Voronoi
└ 001└ 002└ 003└ 004└ 005
11Terrain
└ Simple Polygon└ Simple Flyover└ Infinite Flyover 01└ Infinite Flyover 02└ Hexagonal Plane└ Mountain Ridges
12Critter Models 01
└ Wireframe Spider└ Wireframe Fly└ Wireframe Scorpion└ Wireframe Mosquito└ Wireframe Bee└ Wireframe Butterfly└ Wireframe Locust
13Chromatophores
└ 01└ 02└ 03└ 04
14Conformal Maps
└ 01└ 02└ 03└ 04└ 05
02 / 03

BROKEN SOLID - RETROSCOPIC CRT SHADER SOURCE CODE

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <style>
        body { margin: 0; overflow: hidden; background: #000; }
        #stage {
            position: fixed;
            inset: 0;
            width: 100vw;
            height: 100vh;
            filter: grayscale(1) sepia(1) hue-rotate(80deg) saturate(5) brightness(1.15) contrast(1.2);
            z-index: 2;
        }
        /* Retroscopic Overlay */
        #scope {
            position: fixed;
            inset: 0;
            z-index: 4;
            pointer-events: none;
            display: block;
        }
        #scope>div {
            position: absolute;
            inset: 0;
        }
        #scope .glow {
            background: radial-gradient(circle at 50% 46%, rgba(30, 255, 130, .08), rgba(0, 0, 0, 0) 62%);
            animation: nvflick 3.6s steps(24) infinite;
        }
        #scope .scan {
            background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0) 0 2px, rgba(0, 25, 8, .45) 2px 3px);
            animation: nvscan 7s linear infinite;
        }
        #scope .vig {
            box-shadow: inset 0 0 200px 50px rgba(0, 0, 0, .8);
        }
        #scope .mask {
            background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0) 54%, rgba(0, 0, 0, .5) 72%, rgba(0, 0, 0, .94) 100%);
        }
        @keyframes nvscan {
            from { background-position: 0 0; }
            to { background-position: 0 240px; }
        }
        @keyframes nvflick {
            0%, 100% { opacity: .55; }
            40% { opacity: .9; }
            62% { opacity: .4; }
            80% { opacity: .75; }
        }
    </style>
</head>
<body>
    <div id="scope">
        <div class="glow"></div>
        <div class="scan"></div>
        <div class="vig"></div>
        <div class="mask"></div>
    </div>
    <div id="stage"></div>
    <script>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.getElementById('stage').appendChild(renderer.domElement);

        scene.add(new THREE.AmbientLight(0xffffff, 0.6));
        const light = new THREE.DirectionalLight(0xffffff, 0.8);
        light.position.set(5, 5, 5);
        scene.add(light);

        const a = 3;
        const vertices = [
            new THREE.Vector3(a, a, 3*a),
            new THREE.Vector3(a, 3*a, a),
            new THREE.Vector3(3*a, a, a),
            new THREE.Vector3(-a, -a, 3*a),
            new THREE.Vector3(-a, 3*a, -a),
            new THREE.Vector3(3*a, -a, -a),
            new THREE.Vector3(a, -a, -3*a),
            new THREE.Vector3(a, -3*a, -a),
            new THREE.Vector3(-3*a, -a, -a),
            new THREE.Vector3(-a, a, -3*a),
            new THREE.Vector3(-a, -3*a, a),
            new THREE.Vector3(-3*a, a, a)
        ];

        vertices.forEach(v => v.multiplyScalar(0.2));

        const indices = [
            // Triangle faces
            0, 1, 2,
            3, 4, 5,
            6, 7, 8,
            9, 10, 11,

            0, 3, 5,  0, 5, 2,  0, 2, 4,  0, 4, 3,

            1, 0, 4,  1, 4, 7,  1, 7, 10, 1, 10, 0,

            2, 1, 7,  2, 7, 6,  2, 6, 5,  2, 5, 1,

            3, 8, 11, 3, 11, 9, 3, 9, 4,  3, 4, 8
        ];

        const geometry = new THREE.BufferGeometry();
        const positions = [];
        vertices.forEach(v => positions.push(v.x, v.y, v.z));
        geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
        geometry.setIndex(indices);
        geometry.computeVertexNormals();

        const faceMaterial = new THREE.MeshPhongMaterial({
            color: 0x00bcd4,
            transparent: true,
            opacity: 0.9
        });

        const wireMaterial = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            wireframe: true,
            transparent: true,
            opacity: 0.3
        });

        const shape = new THREE.Group();
        shape.add(new THREE.Mesh(geometry, faceMaterial));
        shape.add(new THREE.Mesh(geometry, wireMaterial));
        scene.add(shape);

        camera.position.z = 4;

        function animate() {
            requestAnimationFrame(animate);
            shape.rotation.x += 0.005;
            shape.rotation.y += 0.01;
            renderer.render(scene, camera);
        }

        animate();

        window.addEventListener('resize', () => {
            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.