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.
Reviews
There are no reviews yet. Be the first one to write one.