How to make Interactive 3D Fractals using HTML, CSS, JS

Piyush608 top freelancer india 1 1

Creating interactive 3D fractals using HTML, CSS, and JavaScript can be achieved by leveraging WebGL (Web Graphics Library) along with libraries like Three.js, which simplifies 3D rendering in the browser. Below is a step-by-step guide to get you started on creating an interactive 3D fractal

 

Index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3d Fractals</title>


</head>

<body>
    <button id="panelToggle">☰</button>
<div id="configPanel">
    <div id="controls">
        <h2>Configurations</h2>
        <div class="control">
            <div class="control-header">
                <label for="colorPicker">Color:</label>
                <input type="color" id="colorPicker" value="#ffffff">
                <span id="colorValue" class="value-display">#FFFFFF</span>
            </div>
        </div>
        <div class="control">
            <button id="rainbowColor">Disable Rainbow Color</button>
        </div>
        <div class="control">
            <div class="control-header">
                <label for="size">Scale:</label>
                <span id="sizeValue" class="value-display">4.0</span>
            </div>
            <input type="range" id="size" min="1" max="20" value="4" step="0.1">
        </div>
        <div class="control">
            <div class="control-header">
                <label for="complexity">Complexity:</label>
                <span id="complexityValue" class="value-display">4</span>
            </div>
            <input type="range" id="complexity" min="1" max="6" value="4" step="1">
        </div>
        <div class="control">
            <div class="control-header">
                <label for="zoom">Depth:</label>
                <span id="zoomValue" class="value-display">10.0</span>
            </div>
            <input type="range" id="zoom" min="0.1" max="20" value="5" step="0.1">
        </div>
        <div class="control">
            <div class="control-header">
                <label for="rotationSpeed">Rotation Speed:</label>
                <span id="rotationSpeedValue" class="value-display">0.005</span>
            </div>
            <input type="range" id="rotationSpeed" min="0" max="0.05" value="0.005" step="0.001">
        </div>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>


</body>

</html>

 

Stlye.css

@import url("https://fonts.googleapis.com/css2?family=Lato&display=swap");

body {
    margin: 0;
    overflow: hidden;
    font-family: Lato, sans-serif;
}
canvas {
    display: block;
}
#configPanel {
    position: fixed;
    top: 0;
    left: 0;
    width: 250px;
    height: 100%;
    background-color: rgba(30, 30, 30, 0.9);
    color: white;
    transition: left 0.3s ease-in-out;
    overflow-y: auto;
    z-index: 1000;
}
#configPanel.closed {
    left: -250px;
}
#panelToggle {
    position: fixed;
    top: 10px;
    left: 260px;
    width: 30px;
    height: 30px;
    background-color: rgba(30, 30, 30, 0.7);
    color: white;
    border: none;
    padding: 0;
    font-size: 18px;
    cursor: pointer;
    z-index: 1001;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: background-color 0.3s, left 0.3s ease-in-out;
}
#panelToggle:hover {
    background-color: rgba(50, 50, 50, 0.9);
}
#panelToggle.closed {
    left: 10px;
}
#controls {
    padding: 20px;
}
.control {
    margin-bottom: 20px;
}
.control-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 5px;
}
label {
    display: inline-block;
}
input[type="range"] {
    width: 100%;
}
button {
    width: 100%;
    padding: 10px;
    background-color: #4caf50;
    color: white;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s;
}
button:hover {
    background-color: #45a049;
}
.value-display {
    font-weight: bold;
}

 

Javascript

<script>
// Set up the scene, camera, and renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Configuration variables
let pyramidColor = 0xffffff;
let pyramidSize = 4;
let pyramidComplexity = 4;
let rotationSpeed = 0.005;
let isRainbowColor = true;
let rainbowOffset = 0;
let zoom = 5;

// Create a function to generate the Sierpinski pyramid
function createSierpinskiPyramid(depth, size, x, y, z) {
    if (depth === 0) {
        const geometry = new THREE.TetrahedronGeometry(size);
        const material = new THREE.LineBasicMaterial({ color: pyramidColor });
        const tetrahedron = new THREE.LineSegments(
            new THREE.EdgesGeometry(geometry),
            material
        );
        tetrahedron.position.set(x, y, z);
        return tetrahedron;
    } else {
        const group = new THREE.Group();
        const newSize = size / 2;
        const offset = newSize / 2;

        group.add(
            createSierpinskiPyramid(
                depth - 1,
                newSize,
                x + offset,
                y + offset,
                z + offset
            )
        );
        group.add(
            createSierpinskiPyramid(
                depth - 1,
                newSize,
                x - offset,
                y - offset,
                z + offset
            )
        );
        group.add(
            createSierpinskiPyramid(
                depth - 1,
                newSize,
                x + offset,
                y - offset,
                z - offset
            )
        );
        group.add(
            createSierpinskiPyramid(
                depth - 1,
                newSize,
                x - offset,
                y + offset,
                z - offset
            )
        );

        return group;
    }
}

// Generate the initial Sierpinski pyramid
let pyramid = createSierpinskiPyramid(pyramidComplexity, pyramidSize, 0, 0, 0);
scene.add(pyramid);

// Position the camera
camera.position.z = zoom;

// Add ambient light to the scene
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

// Add directional light to the scene
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);

// Animation loop
function animate() {
    requestAnimationFrame(animate);

    // Rotate the entire scene
    scene.rotation.x += rotationSpeed;
    scene.rotation.y += rotationSpeed;

    if (isRainbowColor) {
        rainbowOffset += 0.01;
        updateRainbowColor();
    }

    renderer.render(scene, camera);
}

animate();

// Handle window resizing
window.addEventListener("resize", onWindowResize, false);

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

// Configuration panel functionality
const panelToggle = document.getElementById("panelToggle");
const configPanel = document.getElementById("configPanel");
panelToggle.addEventListener("click", () => {
    configPanel.classList.toggle("closed");
    panelToggle.classList.toggle("closed");
});

// Color picker
const colorPicker = document.getElementById("colorPicker");
const colorValue = document.getElementById("colorValue");
colorPicker.addEventListener("input", (e) => {
    pyramidColor = parseInt(e.target.value.substr(1), 16);
    colorValue.textContent = e.target.value.toUpperCase();
    isRainbowColor = false;
    updatePyramid();
    rainbowColorBtn.textContent = "Enable Rainbow Color";
});

// Rainbow color
const rainbowColorBtn = document.getElementById("rainbowColor");
rainbowColorBtn.addEventListener("click", () => {
    isRainbowColor = !isRainbowColor;
    rainbowColorBtn.textContent = isRainbowColor
        ? "Disable Rainbow Color"
        : "Enable Rainbow Color";
    if (!isRainbowColor) {
        pyramidColor = parseInt(colorPicker.value.substr(1), 16);
        updatePyramid();
    }
});

// Size
const sizeInput = document.getElementById("size");
const sizeValue = document.getElementById("sizeValue");
sizeInput.value = pyramidSize;
sizeValue.textContent = pyramidSize.toFixed(1);
sizeInput.addEventListener("input", (e) => {
    pyramidSize = parseFloat(e.target.value);
    sizeValue.textContent = pyramidSize.toFixed(1);
    updatePyramid();
});

// Complexity
const complexityInput = document.getElementById("complexity");
const complexityValue = document.getElementById("complexityValue");
complexityValue.textContent = pyramidComplexity;
complexityInput.addEventListener("input", (e) => {
    pyramidComplexity = parseInt(e.target.value);
    complexityValue.textContent = pyramidComplexity;
    updatePyramid();
});

// Zoom
const zoomInput = document.getElementById("zoom");
const zoomValue = document.getElementById("zoomValue");
zoomInput.value = zoom;
zoomValue.textContent = zoom.toFixed(1);
zoomInput.addEventListener("input", (e) => {
    zoom = parseFloat(e.target.value);
    zoomValue.textContent = zoom.toFixed(1);
    camera.position.z = zoom;
});

// Rotation speed
const rotationSpeedInput = document.getElementById("rotationSpeed");
const rotationSpeedValue = document.getElementById("rotationSpeedValue");
rotationSpeedValue.textContent = rotationSpeed.toFixed(3);
rotationSpeedInput.addEventListener("input", (e) => {
    rotationSpeed = parseFloat(e.target.value);
    rotationSpeedValue.textContent = rotationSpeed.toFixed(3);
});

function updatePyramid() {
    scene.remove(pyramid);
    pyramid = createSierpinskiPyramid(pyramidComplexity, pyramidSize, 0, 0, 0);
    scene.add(pyramid);
}

function updateRainbowColor() {
    pyramid.traverse((child) => {
        if (child instanceof THREE.LineSegments) {
            const hue =
                (rainbowOffset + child.position.x + child.position.y + child.position.z) %
                1;
            child.material.color.setHSL(hue, 1, 0.5);
        }
    });
}

// Initialize with rainbow color
updateRainbowColor();

</script>

 

Customize and Expand

Feel free to customize the fractal generation logic, materials, lighting, and more to create more complex and visually appealing fractals. You can experiment with different fractal algorithms, shaders, and interactive elements to enhance the visual experience.

Conclusion

This guide provides a basic setup for creating interactive 3D fractals using HTML, CSS, and JavaScript with Three.js. By expanding on this foundation, you can create intricate and beautiful fractal patterns and enable users to interact with them in various ways.

CEO Piyush Gupta


Reviews

There are no reviews yet. Be the first one to write one.


0.0
Rated 0 out of 5
0 out of 5 stars (based on 0 reviews)
Excellent0%
Very good0%
Average0%
Poor0%
Terrible0%