← Mike Higgins Home
Custom Code Experiment •

3D Net

Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>3D Net</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            font-family: 'Segoe UI', 'Inter', system-ui, -apple-system, sans-serif;
        }
        canvas {
            display: block;
            outline: none;
        }
        .info {
            position: absolute;
            bottom: 20px;
            left: 20px;
            color: rgba(255, 255, 255, 0.65);
            background: rgba(0, 0, 0, 0.5);
            backdrop-filter: blur(6px);
            padding: 6px 14px;
            border-radius: 40px;
            font-size: 13px;
            pointer-events: none;
            z-index: 10;
            font-weight: 400;
            letter-spacing: 0.3px;
            font-family: monospace;
        }
        .info a {
            color: #ff9c66;
            text-decoration: none;
            pointer-events: auto;
        }
        @media (max-width: 600px) {
            .info { font-size: 10px; bottom: 12px; left: 12px; }
        }
    </style>
</head>
<body>
    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/three@0.128.0/build/three.module.js"
            }
        }
    </script>

    <script type="module">
        import * as THREE from 'three';

        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x000000);

        const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        document.body.appendChild(renderer.domElement);

        const ambientLight = new THREE.AmbientLight(0xffffff, 0.45);
        scene.add(ambientLight);

        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.9);
        directionalLight.position.set(1, 2, 1.5);
        scene.add(directionalLight);

        const backLight = new THREE.PointLight(0xffaa66, 0.6);
        backLight.position.set(-30, 20, -40);
        scene.add(backLight);

        const fillLight = new THREE.PointLight(0x66aaff, 0.4);
        fillLight.position.set(0, -60, 0);
        scene.add(fillLight);

        const movingLight = new THREE.PointLight(0xff8855, 0.55);
        movingLight.position.set(40, 30, 50);
        scene.add(movingLight);

        function createNeuralNetwork(layers, nodesPerLayer, maxNodeSize) {
            const group = new THREE.Group();
            const sphereRadiusGlobal = 50;

            const nodeMaterial = new THREE.MeshPhongMaterial({
                color: 0xFF9C66,
                shininess: 70,
                emissive: 0x221100,
                flatShading: false
            });

            const lineMaterial = new THREE.LineBasicMaterial({ color: 0xFFFFFF });

            const layersNodes = [];

            for (let i = 0; i < layers; i++) {
                const currentLayerNodes = [];
                const theta = (Math.PI * 2 * i) / layers;
                const sinTheta = Math.sin(theta);
                const cosTheta = Math.cos(theta);

                for (let j = 0; j < nodesPerLayer; j++) {
                    const phi = (Math.PI * 2 * j) / nodesPerLayer;
                    const sinPhi = Math.sin(phi);
                    const cosPhi = Math.cos(phi);

                    const xPos = sphereRadiusGlobal * sinTheta * cosPhi;
                    const yPos = sphereRadiusGlobal * sinTheta * sinPhi;
                    const zPos = sphereRadiusGlobal * cosTheta;

                    const radius = Math.max(0.35, Math.random() * maxNodeSize);
                    const geometry = new THREE.SphereGeometry(radius, 24, 18);
                    const node = new THREE.Mesh(geometry, nodeMaterial);
                    node.position.set(xPos, yPos, zPos);

                    group.add(node);
                    currentLayerNodes.push(node);
                }
                layersNodes.push(currentLayerNodes);
            }

            for (let layerIdx = 1; layerIdx < layers; layerIdx++) {
                const prevLayerNodes = layersNodes[layerIdx - 1];
                const currLayerNodes = layersNodes[layerIdx];

                for (let currNode of currLayerNodes) {
                    for (let prevNode of prevLayerNodes) {
                        const pointsArray = [currNode.position.clone(), prevNode.position.clone()];
                        const lineGeometry = new THREE.BufferGeometry().setFromPoints(pointsArray);
                        const line = new THREE.Line(lineGeometry, lineMaterial);
                        group.add(line);
                    }
                }
            }

            return group;
        }

        const neuralNetwork = createNeuralNetwork(10, 15, 2.2);
        scene.add(neuralNetwork);

        const starFieldGeometry = new THREE.BufferGeometry();
        const starCount = 1800;
        const starPositions = new Float32Array(starCount * 3);
        for (let i = 0; i < starCount; i++) {
            starPositions[i*3] = (Math.random() - 0.5) * 600;
            starPositions[i*3+1] = (Math.random() - 0.5) * 400;
            starPositions[i*3+2] = (Math.random() - 0.5) * 300 - 100;
        }
        starFieldGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
        const starMaterial = new THREE.PointsMaterial({ color: 0xaaccff, size: 0.28, transparent: true, opacity: 0.5 });
        const stars = new THREE.Points(starFieldGeometry, starMaterial);
        scene.add(stars);

        const wireframeSphereGeo = new THREE.SphereGeometry(68, 32, 16);
        const wireframeMat = new THREE.MeshBasicMaterial({ color: 0x336699, wireframe: true, transparent: true, opacity: 0.07 });
        const auraSphere = new THREE.Mesh(wireframeSphereGeo, wireframeMat);
        scene.add(auraSphere);

        let angle = 0;
        const orbitRadius = 110;
        const verticalTilt = Math.PI / 9;

        function animateStars() {
            stars.rotation.y += 0.0004;
            stars.rotation.x += 0.0002;
            auraSphere.rotation.y += 0.0006;
            auraSphere.rotation.x += 0.0003;
            movingLight.position.x = 45 * Math.sin(Date.now() * 0.0006);
            movingLight.position.z = 45 * Math.cos(Date.now() * 0.0007);
        }

        function animate() {
            requestAnimationFrame(animate);

            angle += 0.0022;
            const camX = orbitRadius * Math.sin(angle) * Math.cos(verticalTilt);
            const camY = orbitRadius * Math.sin(verticalTilt);
            const camZ = orbitRadius * Math.cos(angle) * Math.cos(verticalTilt);

            camera.position.set(camX, camY, camZ);
            camera.lookAt(0, 0, 0);

            animateStars();

            const intensity = 0.55 + Math.sin(Date.now() * 0.002) * 0.2;
            movingLight.intensity = intensity;

            renderer.render(scene, camera);
        }

        animate();

        window.addEventListener('resize', onWindowResize, false);
        function onWindowResize() {
            const width = window.innerWidth;
            const height = window.innerHeight;
            renderer.setSize(width, height);
            camera.aspect = width / height;
            camera.updateProjectionMatrix();
        }

        console.log('3D Neural Network ready | Layers: 10, Nodes per layer: 15, Connections: 2025');
    </script>
</body>
</html>