diff --git a/threejs/dodeahedron-fractal/extra.js b/threejs/dodeahedron-fractal/extra.js
new file mode 100644
index 00000000..30a13842
--- /dev/null
+++ b/threejs/dodeahedron-fractal/extra.js
@@ -0,0 +1,67 @@
+import * as THREE from 'three';
+import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
+import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
+import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
+
+
+// Setup Scene, Camera, 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);
+
+// Postprocessing with Bloom effect
+const composer = new EffectComposer(renderer);
+const renderPass = new RenderPass(scene, camera);
+composer.addPass(renderPass);
+
+const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+composer.addPass(bloomPass);
+
+// Create Material and Line Geometry
+const material = new THREE.LineBasicMaterial({ color: 0xffd700 }); // Golden color
+
+// Set up the Golden Ratio Dragon Curve parameters
+const goldenRatio = (1 + Math.sqrt(5)) / 2;
+const r1 = Math.pow(1 / goldenRatio, 1 / goldenRatio);
+const r2 = Math.pow(r1, 2);
+const angle1 = Math.acos((1 + r1**2 - r1**4) / (2 * r1));
+const angle2 = Math.acos((1 + r1**4 - r1**2) / (2 * r1**2));
+
+function goldenDragon(x1, y1, x2, y2, turn, n, vertices) {
+ const dist = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+ if (dist < 1 || n <= 0) {
+ vertices.push(new THREE.Vector3(x2, y2, 0));
+ return;
+ }
+
+ const angle = Math.atan2(y2 - y1, x2 - x1);
+ let px, py;
+ if (turn) {
+ px = x1 + dist * r1 * Math.cos(angle + angle1);
+ py = y1 + dist * r1 * Math.sin(angle + angle1);
+ } else {
+ px = x1 + dist * r2 * Math.cos(angle - angle2);
+ py = y1 + dist * r2 * Math.sin(angle - angle2);
+ }
+
+ goldenDragon(x1, y1, px, py, true, n - 1, vertices);
+ goldenDragon(px, py, x2, y2, false, n - 1, vertices);
+}
+
+// Setup the geometry to hold the vertices
+const points = [];
+goldenDragon(-5, -2, 15, -2, true, 10, points); // Adjust the recursion level as needed
+const geometry = new THREE.BufferGeometry().setFromPoints(points);
+const line = new THREE.Line(geometry, material);
+scene.add(line);
+
+// Position the camera and animate
+camera.position.z = 10;
+
+function animate() {
+ requestAnimationFrame(animate);
+ composer.render();
+}
+animate();
\ No newline at end of file
diff --git a/threejs/dodeahedron-fractal/getLayer.js b/threejs/dodeahedron-fractal/getLayer.js
new file mode 100644
index 00000000..9233ed8b
--- /dev/null
+++ b/threejs/dodeahedron-fractal/getLayer.js
@@ -0,0 +1,55 @@
+/**
+ * Based upon Bobby Roe's Simple Particle System
+ * Watch the tutorial on YouTube: (https://youtu.be/h1UQdbuF204)
+ */
+
+import * as THREE from "three";
+
+const loader = new THREE.TextureLoader();
+
+function getSprite({ hasFog, color, opacity, path, pos, size }) {
+ const spriteMat = new THREE.SpriteMaterial({
+ color,
+ fog: hasFog,
+ map: loader.load(path),
+ transparent: true,
+ opacity,
+ });
+ spriteMat.color.offsetHSL(0, 0, Math.random() * 0.2 - 0.1);
+ const sprite = new THREE.Sprite(spriteMat);
+ sprite.position.set(pos.x, -pos.y, pos.z);
+ size += Math.random() - 0.5;
+ sprite.scale.set(size, size, size);
+ sprite.material.rotation = 0;
+ return sprite;
+}
+
+function getLayer({
+ hasFog = true,
+ hue = 0.0,
+ numSprites = 10,
+ opacity = 1,
+ path = "./img/rad-grad.png",
+ radius = 1,
+ sat = 0.5,
+ size = 1,
+ z = 0,
+}) {
+ const layerGroup = new THREE.Group();
+ for (let i = 0; i < numSprites; i += 1) {
+ let angle = (i / numSprites) * Math.PI * 2;
+ const pos = new THREE.Vector3(
+ Math.cos(angle) * Math.random() * radius,
+ Math.sin(angle) * Math.random() * radius,
+ z + Math.random()
+ );
+ const length = new THREE.Vector3(pos.x, pos.y, 0).length();
+ // const hue = 0.0; // (0.9 - (radius - length) / radius) * 1;
+
+ let color = new THREE.Color().setHSL(hue, 1, sat);
+ const sprite = getSprite({ hasFog, color, opacity, path, pos, size });
+ layerGroup.add(sprite);
+ }
+ return layerGroup;
+}
+export default getLayer;
\ No newline at end of file
diff --git a/threejs/dodeahedron-fractal/getParticleSystem.js b/threejs/dodeahedron-fractal/getParticleSystem.js
new file mode 100644
index 00000000..179d2cd0
--- /dev/null
+++ b/threejs/dodeahedron-fractal/getParticleSystem.js
@@ -0,0 +1,236 @@
+/**
+ * Based upon Bobby Roe's Simple Particle System
+ * Watch the tutorial on YouTube: (https://youtu.be/h1UQdbuF204)
+ */
+
+import * as THREE from 'three';
+
+const _VS = `
+uniform float pointMultiplier;
+
+attribute float size;
+attribute float angle;
+attribute vec4 aColor;
+
+varying vec4 vColor;
+varying vec2 vAngle;
+
+void main() {
+ vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
+
+ gl_Position = projectionMatrix * mvPosition;
+ gl_PointSize = size * pointMultiplier / gl_Position.w;
+
+ vAngle = vec2(cos(angle), sin(angle));
+ vColor = aColor;
+}`;
+
+const _FS = `
+uniform sampler2D diffuseTexture;
+
+varying vec4 vColor;
+varying vec2 vAngle;
+
+void main() {
+ vec2 coords = (gl_PointCoord - 0.5) * mat2(vAngle.x, vAngle.y, -vAngle.y, vAngle.x) + 0.5;
+ gl_FragColor = texture2D(diffuseTexture, coords) * vColor;
+}`;
+
+
+function getLinearSpline(lerp) {
+
+ const points = [];
+ const _lerp = lerp;
+
+ function addPoint(t, d) {
+ points.push([t, d]);
+ }
+
+ function getValueAt(t) {
+ let p1 = 0;
+
+ for (let i = 0; i < points.length; i++) {
+ if (points[i][0] >= t) {
+ break;
+ }
+ p1 = i;
+ }
+
+ const p2 = Math.min(points.length - 1, p1 + 1);
+
+ if (p1 == p2) {
+ return points[p1][1];
+ }
+
+ return _lerp(
+ (t - points[p1][0]) / (
+ points[p2][0] - points[p1][0]),
+ points[p1][1], points[p2][1]);
+ }
+ return { addPoint, getValueAt };
+}
+
+function getParticleSystem(params) {
+ const { camera, emitter, parent, rate, texture } = params;
+ const uniforms = {
+ diffuseTexture: {
+ value: new THREE.TextureLoader().load(texture)
+ },
+ pointMultiplier: {
+ value: window.innerHeight / (2.0 * Math.tan(30.0 * Math.PI / 180.0))
+ }
+ };
+ const _material = new THREE.ShaderMaterial({
+ uniforms: uniforms,
+ vertexShader: _VS,
+ fragmentShader: _FS,
+ //blending: THREE.AdditiveBlending,
+ depthTest: true,
+ depthWrite: false,
+ transparent: true,
+ vertexColors: true
+ });
+
+ let _particles = [];
+
+ const geometry = new THREE.BufferGeometry();
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
+ geometry.setAttribute('size', new THREE.Float32BufferAttribute([], 1));
+ geometry.setAttribute('aColor', new THREE.Float32BufferAttribute([], 4));
+ geometry.setAttribute('angle', new THREE.Float32BufferAttribute([], 1));
+
+ const _points = new THREE.Points(geometry, _material);
+
+ parent.add(_points);
+
+ const alphaSpline = getLinearSpline((t, a, b) => {
+ return a + t * (b - a);
+ });
+ alphaSpline.addPoint(0.0, 0.0);
+ alphaSpline.addPoint(0.6, 1.0);
+ alphaSpline.addPoint(1.0, 0.0);
+
+ const colorSpline = getLinearSpline((t, a, b) => {
+ const c = a.clone();
+ return c.lerp(b, t);
+ });
+ colorSpline.addPoint(0.0, new THREE.Color(0xffff00));
+ colorSpline.addPoint(0.0, new THREE.Color(0x00ff00));
+ colorSpline.addPoint(0.0, new THREE.Color(0x00ffff));
+ colorSpline.addPoint(1.0, new THREE.Color(0xffffff));
+
+ const sizeSpline = getLinearSpline((t, a, b) => {
+ return a + t * (b - a);
+ });
+ sizeSpline.addPoint(0.0, 0.0);
+ sizeSpline.addPoint(1.0, 1.0);
+ // max point size = 512; => console.log(ctx.getParameter(ctx.ALIASED_POINT_SIZE_RANGE));
+ const maxVelocity = 1.5;
+ const radius = 0.5;
+ const maxLife = 9.5;
+ const maxSize = 0.15;
+ let gdfsghk = 0.0;
+ function _AddParticles(timeElapsed) {
+ gdfsghk += timeElapsed;
+ const n = Math.floor(gdfsghk * rate);
+ gdfsghk -= n / rate;
+ for (let i = 0; i < n; i += 1) {
+ const life = (Math.random() * 0.75 + 0.25) * maxLife;
+ _particles.push({
+ position: new THREE.Vector3(
+ (Math.random() * 2 - 1) * radius,
+ (Math.random() * 2 - 1) * radius,
+ (Math.random() * 2 - 1) * radius).add(emitter.position),
+ size: (Math.random() * 0.5 + 0.5) * maxSize,
+ colour: new THREE.Color(),
+ alpha: 1.0,
+ life: life,
+ maxLife: life,
+ rotation: Math.random() * 2.0 * Math.PI,
+ rotationRate: Math.random() * 0.01 - 0.005,
+ velocity: new THREE.Vector3(
+ (Math.random() * 2 - 1) * radius * maxVelocity,
+ (Math.random() * 2 - 1) * radius * maxVelocity,
+ (Math.random() * 2 - 1) * radius * maxVelocity),
+ });
+ }
+ }
+
+ function _UpdateGeometry() {
+ const positions = [];
+ const sizes = [];
+ const colours = [];
+ const angles = [];
+
+ for (let p of _particles) {
+ positions.push(p.position.x, p.position.y, p.position.z);
+ colours.push(p.colour.r, p.colour.g, p.colour.b, p.alpha);
+ sizes.push(p.currentSize);
+ angles.push(p.rotation);
+ }
+
+ geometry.setAttribute(
+ 'position', new THREE.Float32BufferAttribute(positions, 3));
+ geometry.setAttribute(
+ 'size', new THREE.Float32BufferAttribute(sizes, 1));
+ geometry.setAttribute(
+ 'aColor', new THREE.Float32BufferAttribute(colours, 4));
+ geometry.setAttribute(
+ 'angle', new THREE.Float32BufferAttribute(angles, 1));
+
+ geometry.attributes.position.needsUpdate = true;
+ geometry.attributes.size.needsUpdate = true;
+ geometry.attributes.aColor.needsUpdate = true;
+ geometry.attributes.angle.needsUpdate = true;
+ }
+ _UpdateGeometry();
+
+ function _UpdateParticles(timeElapsed) {
+ for (let p of _particles) {
+ p.life -= timeElapsed;
+ }
+
+ _particles = _particles.filter(p => {
+ return p.life > 0.0;
+ });
+
+ for (let p of _particles) {
+ const t = 1.0 - p.life / p.maxLife;
+ p.rotation += p.rotationRate;
+ p.alpha = alphaSpline.getValueAt(t);
+ p.currentSize = p.size * sizeSpline.getValueAt(t);
+ p.colour.copy(colorSpline.getValueAt(t));
+
+ p.position.add(p.velocity.clone().multiplyScalar(timeElapsed));
+
+ const drag = p.velocity.clone();
+ drag.multiplyScalar(timeElapsed * 0.1);
+ drag.x = Math.sign(p.velocity.x) * Math.min(Math.abs(drag.x), Math.abs(p.velocity.x));
+ drag.y = Math.sign(p.velocity.y) * Math.min(Math.abs(drag.y), Math.abs(p.velocity.y));
+ drag.z = Math.sign(p.velocity.z) * Math.min(Math.abs(drag.z), Math.abs(p.velocity.z));
+ p.velocity.sub(drag);
+ }
+
+ _particles.sort((a, b) => {
+ const d1 = camera.position.distanceTo(a.position);
+ const d2 = camera.position.distanceTo(b.position);
+
+ if (d1 > d2) {
+ return -1;
+ }
+ if (d1 < d2) {
+ return 1;
+ }
+ return 0;
+ });
+ }
+
+ function update(timeElapsed) {
+ _AddParticles(timeElapsed);
+ _UpdateParticles(timeElapsed);
+ _UpdateGeometry();
+ }
+ return { update };
+}
+
+export { getParticleSystem };
\ No newline at end of file
diff --git a/threejs/dodeahedron-fractal/img/circle.png b/threejs/dodeahedron-fractal/img/circle.png
new file mode 100644
index 00000000..89c7d9ac
Binary files /dev/null and b/threejs/dodeahedron-fractal/img/circle.png differ
diff --git a/threejs/dodeahedron-fractal/img/fire.png b/threejs/dodeahedron-fractal/img/fire.png
new file mode 100644
index 00000000..cd17c701
Binary files /dev/null and b/threejs/dodeahedron-fractal/img/fire.png differ
diff --git a/threejs/dodeahedron-fractal/img/rad-grad.png b/threejs/dodeahedron-fractal/img/rad-grad.png
new file mode 100644
index 00000000..ab95e3e0
Binary files /dev/null and b/threejs/dodeahedron-fractal/img/rad-grad.png differ
diff --git a/threejs/dodeahedron-fractal/img/smoke.png b/threejs/dodeahedron-fractal/img/smoke.png
new file mode 100644
index 00000000..6ab10205
Binary files /dev/null and b/threejs/dodeahedron-fractal/img/smoke.png differ
diff --git a/threejs/dodeahedron-fractal/index.html b/threejs/dodeahedron-fractal/index.html
new file mode 100644
index 00000000..240973db
--- /dev/null
+++ b/threejs/dodeahedron-fractal/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ Icosahedron - Fractal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/threejs/dodeahedron-fractal/script.js b/threejs/dodeahedron-fractal/script.js
new file mode 100644
index 00000000..3818c609
--- /dev/null
+++ b/threejs/dodeahedron-fractal/script.js
@@ -0,0 +1,447 @@
+import * as THREE from 'three';
+import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
+import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
+import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
+import getLayer from "./getLayer.js";
+import { getParticleSystem } from "./getParticleSystem.js";
+
+
+let scene, camera, renderer, composer, fractalLine;
+let n = 1;
+let increasing = true;
+const maxN = 25;
+const speed = 0.03; // Adjust this value to control the speed of n's change
+let fireEffect;
+
+init();
+animate();
+
+
+function init() {
+ // Scene setup
+ scene = new THREE.Scene();
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+ camera.position.z = 5;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ document.body.appendChild(renderer.domElement);
+
+ // Controls
+ const controls = new OrbitControls(camera, renderer.domElement);
+ controls.enableDamping = true;
+
+ // Icosahedron Geometry
+ //const geometry = new THREE.IcosahedronGeometry(1);
+ const geometry = new THREE.DodecahedronGeometry(1);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
+
+ const edges = new THREE.EdgesGeometry(geometry);
+ const line = new THREE.LineSegments(edges, lineMaterial);
+ scene.add(line);
+
+ fireEffect = getParticleSystem({
+ camera,
+ emitter: line,
+ parent: scene,
+ rate: 50.0,
+ texture: 'img/circle.png',
+ });
+
+ // Glow Effect (Bloom)
+ composer = new EffectComposer(renderer);
+ const renderPass = new RenderPass(scene, camera);
+ composer.addPass(renderPass);
+
+ const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+ bloomPass.threshold = 0;
+ bloomPass.strength = 2; // Intensity of the bloom
+ bloomPass.radius = 0.9;
+ composer.addPass(bloomPass);
+
+ // Handle window resize
+ window.addEventListener('resize', onWindowResize);
+}
+
+function animate() {
+ requestAnimationFrame(animate);
+
+ // Rotate the icosahedron
+ scene.children[0].rotation.y += 0.001;
+ scene.children[0].rotation.x -= 0.002;
+ scene.children[0].rotation.z += 0.002;
+
+ // Update fractal
+ updateFractal();
+ fireEffect.update(0.016);
+ composer.render();
+}
+
+function updateFractal() {
+ // Remove previous fractal
+ const fractal = scene.getObjectByName('fractal');
+ if (fractal) {
+ scene.remove(fractal);
+ }
+
+ // Generate new fractal with updated n
+ const vertices = [];
+ goldenDragon(-5, 0, 5, 0, true, Math.floor(n), vertices);
+
+ const fractalGeometry = new THREE.BufferGeometry().setFromPoints(vertices);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
+ const fractalLine = new THREE.Line(fractalGeometry, lineMaterial);
+ fractalLine.position.z = -5; // Position behind the icosahedron
+ fractalLine.position.y = -1;
+ fractalLine.position.x = 2;
+ const s = 1.2;
+ fractalLine.scale.set(s,s,s); // Adjust the scale of the fractal
+ fractalLine.name = 'fractal';
+ scene.add(fractalLine);
+
+ // Update n
+ if (increasing) {
+ n += speed;
+ if (n >= maxN) {
+ increasing = false;
+ }
+ } else {
+ n -= speed;
+ if (n <= 1) {
+ increasing = true;
+ }
+ }
+}
+
+function goldenDragon(x1, y1, x2, y2, turn, n, vertices) {
+ const goldenRatio = (1 + Math.sqrt(5)) / 2;
+ const r1 = Math.pow(1 / goldenRatio, 1 / goldenRatio);
+ const r2 = Math.pow(r1, 2);
+ const angle1 = Math.acos((1 + r1**2 - r1**4) / (2 * r1));
+ const angle2 = Math.acos((1 + r1**4 - r1**2) / (2 * r2));
+
+ const dist = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+ if (dist < 0.05 || n <= 0) {
+ vertices.push(new THREE.Vector3(x2, y2, 0));
+ return;
+ }
+
+ const angle = Math.atan2(y2 - y1, x2 - x1);
+ let px, py;
+ if (turn) {
+ px = x1 + dist * r1 * Math.cos(angle + angle1);
+ py = y1 + dist * r1 * Math.sin(angle + angle1);
+ } else {
+ px = x1 + dist * r2 * Math.cos(angle - angle2);
+ py = y1 + dist * r2 * Math.sin(angle - angle2);
+ }
+
+ vertices.push(new THREE.Vector3(x1, y1, 0));
+ goldenDragon(x1, y1, px, py, true, n - 1, vertices);
+ goldenDragon(px, py, x2, y2, false, n - 1, vertices);
+}
+
+function onWindowResize() {
+ camera.aspect = window.innerWidth / window.innerHeight;
+ camera.updateProjectionMatrix();
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ composer.setSize(window.innerWidth, window.innerHeight);
+}
+/*
+let scene, camera, renderer, composer;
+
+
+init();
+animate();
+
+function init() {
+ // Scene setup
+ scene = new THREE.Scene();
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+ camera.position.z = 5;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ document.body.appendChild(renderer.domElement);
+
+ // Controls
+ const controls = new OrbitControls(camera, renderer.domElement);
+ controls.enableDamping = true;
+
+ // Icosahedron Geometry
+ const geometry = new THREE.IcosahedronGeometry(1);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
+
+ const edges = new THREE.EdgesGeometry(geometry);
+ const line = new THREE.LineSegments(edges, lineMaterial);
+ scene.add(line);
+
+ // Generate Golden Ratio Dragon fractal
+ const points = [];
+ goldenDragon(-5, -2, 7, -2, true, 20, points);
+ const fractalGeometry = new THREE.BufferGeometry().setFromPoints(points);
+ const fractalLine = new THREE.Line(fractalGeometry, lineMaterial);
+ fractalLine.position.z = -5; // Position behind the icosahedron
+ fractalLine.position.x = 1.5; // Position behind the icosahedron
+ fractalLine.position.y = 0.5; // Position behind the icosahedron
+ let s = 1.5;
+ fractalLine.scale.set(s, s, s);
+ scene.add(fractalLine);
+
+ // Glow Effect (Bloom)
+ composer = new EffectComposer(renderer);
+ const renderPass = new RenderPass(scene, camera);
+ composer.addPass(renderPass);
+
+ const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+ bloomPass.threshold = 0;
+ bloomPass.strength = 2; // Intensity of the bloom
+ bloomPass.radius = 1;
+ composer.addPass(bloomPass);
+
+ // Handle window resize
+ window.addEventListener('resize', onWindowResize);
+}
+
+function animate() {
+ requestAnimationFrame(animate);
+
+ // Rotate the icosahedron
+ scene.children[0].rotation.y += 0.01;
+
+ composer.render();
+}
+
+function onWindowResize() {
+ camera.aspect = window.innerWidth / window.innerHeight;
+ camera.updateProjectionMatrix();
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ composer.setSize(window.innerWidth, window.innerHeight);
+}
+
+function goldenDragon(x1, y1, x2, y2, turn, n, vertices) {
+ const goldenRatio = (1 + Math.sqrt(5)) / 2;
+ const r1 = Math.pow(1 / goldenRatio, 1 / goldenRatio);
+ const r2 = Math.pow(r1, 2);
+ const angle1 = Math.acos((1 + r1**2 - r1**4) / (2 * r1));
+ const angle2 = Math.acos((1 + r1**4 - r1**2) / (2 * r2));
+
+ const dist = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+ if (dist < 0.1 || n <= 0) {
+ vertices.push(new THREE.Vector3(x2, y2, 0));
+ return;
+ }
+
+ const angle = Math.atan2(y2 - y1, x2 - x1);
+ let px, py;
+ if (turn) {
+ px = x1 + dist * r1 * Math.cos(angle + angle1);
+ py = y1 + dist * r1 * Math.sin(angle + angle1);
+ } else {
+ px = x1 + dist * r2 * Math.cos(angle - angle2);
+ py = y1 + dist * r2 * Math.sin(angle - angle2);
+ }
+
+ goldenDragon(x1, y1, px, py, true, n - 1, vertices);
+ goldenDragon(px, py, x2, y2, false, n - 1, vertices);
+}
+*/
+
+/*
+init();
+animate();
+
+function init() {
+ // Scene setup
+ scene = new THREE.Scene();
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+ camera.position.z = 5;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ document.body.appendChild(renderer.domElement);
+
+ // Controls
+ const controls = new OrbitControls(camera, renderer.domElement);
+ controls.enableDamping = true;
+
+ // Icosahedron Geometry
+ const geometry = new THREE.IcosahedronGeometry(1);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
+
+ const edges = new THREE.EdgesGeometry(geometry);
+ const line = new THREE.LineSegments(edges, lineMaterial);
+ scene.add(line);
+
+ // Generate Golden Ratio Dragon fractal
+ const points = pDragon(12, 1.5, 0, 0, 0x00ffff);
+ const fractalGeometry = new THREE.BufferGeometry().setFromPoints(points);
+ const fractalLine = new THREE.Line(fractalGeometry, lineMaterial);
+ fractalLine.position.z = -5; // Position behind the icosahedron
+ fractalLine.position.x = 3.9; // Position behind the icosahedron
+ fractalLine.position.y = 1; // Position behind the icosahedron
+ let s = 0.2;
+ fractalLine.scale.set(s,s,s);
+ scene.add(fractalLine);
+
+ // Glow Effect (Bloom)
+ composer = new EffectComposer(renderer);
+ const renderPass = new RenderPass(scene, camera);
+ composer.addPass(renderPass);
+
+ const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+ bloomPass.threshold = 0;
+ bloomPass.strength = 2; // Intensity of the bloom
+ bloomPass.radius = 1;
+ composer.addPass(bloomPass);
+
+ // Handle window resize
+ window.addEventListener('resize', onWindowResize);
+}
+
+function animate() {
+ requestAnimationFrame(animate);
+
+ // Rotate the icosahedron
+ scene.children[0].rotation.y += 0.01;
+
+ composer.render();
+}
+
+function onWindowResize() {
+ camera.aspect = window.innerWidth / window.innerHeight;
+ camera.updateProjectionMatrix();
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ composer.setSize(window.innerWidth, window.innerHeight);
+}
+
+function pDragon(order, scale, hShift, vShift, color) {
+ //const phi = (1 + Math.sqrt(5)) / 2; // Golden ratio
+ let c = 0, x = 0, y = 0, d = 1;
+ const n = 1 << order;
+ const points = [];
+ x = y = 0;
+
+ for (let i = 0; i <= n;) {
+ points.push(new THREE.Vector3((x + hShift) * scale, (y + vShift) * scale, 0));
+
+ let c1 = c & 1, c2 = c & 2;
+ let c2x = 1 * d;
+ if (c2 > 0) { c2x = -1 * d; }
+ let c2y = -1 * c2x;
+
+ if (c1 > 0) {
+ y += c2y;
+ } else {
+ x += c2x;
+ }
+
+ i++;
+ c += i / (i & -i);
+ }
+
+ return points;
+}
+
+*/
+
+
+
+/*
+function init() {
+ // Scene setup
+ scene = new THREE.Scene();
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
+ camera.position.z = 5;
+
+ renderer = new THREE.WebGLRenderer({ antialias: true });
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ document.body.appendChild(renderer.domElement);
+
+ // Controls
+ const controls = new OrbitControls(camera, renderer.domElement);
+ controls.enableDamping = true;
+ controls.dampingFactor = 0.03;
+
+ // Icosahedron Geometry
+ const geometry = new THREE.IcosahedronGeometry(1.5);
+ const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
+
+ const edges = new THREE.EdgesGeometry(geometry);
+ const line = new THREE.LineSegments(edges, lineMaterial);
+ scene.add(line);
+
+ // Generate Lévy C curve fractal
+ const maxIteration = 12; // Controls the complexity of the fractal
+ const points = [];
+ c_curve(-2, 0, 4, 0, maxIteration, points);
+ const fractalGeometry = new THREE.BufferGeometry().setFromPoints(points);
+ const fractalLine = new THREE.Line(fractalGeometry, lineMaterial);
+ fractalLine.rotation.z = Math.PI;
+ fractalLine.position.z = -5; // Position behind the icosahedron
+ fractalLine.position.y = 2;
+ fractalLine.scale.set(1.7, 1.7, 1.7);
+
+ scene.add(fractalLine);
+
+ // Glow Effect (Bloom)
+ composer = new EffectComposer(renderer);
+ const renderPass = new RenderPass(scene, camera);
+ composer.addPass(renderPass);
+
+ const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+ bloomPass.threshold = 0;
+ bloomPass.strength = 1.9; // Intensity of the bloom
+ bloomPass.radius = 1;
+ composer.addPass(bloomPass);
+
+ // Handle window resize
+ window.addEventListener('resize', onWindowResize);
+}
+
+function animate() {
+ requestAnimationFrame(animate);
+
+ // Rotate the icosahedron
+ scene.children[0].rotation.y += 0.005;
+ scene.children[0].rotation.z += 0.002;
+
+ composer.render();
+}
+
+function onWindowResize() {
+ camera.aspect = window.innerWidth / window.innerHeight;
+ camera.updateProjectionMatrix();
+ renderer.setSize(window.innerWidth, window.innerHeight);
+ composer.setSize(window.innerWidth, window.innerHeight);
+}
+
+// Function to create Lévy C curve fractal
+function c_curve(x, y, length, angle, iteration, points) {
+ const toRadians = (degrees) => degrees * (Math.PI / 180);
+ const default_angle = 45;
+
+ if (iteration > 0) {
+ length = length / Math.sqrt(2);
+
+ // First recursive call
+ c_curve(x, y, length, angle + default_angle, iteration - 1, points);
+
+ // Update x, y coordinates
+ x = x + length * Math.cos(toRadians(angle + default_angle));
+ y = y + length * Math.sin(toRadians(angle + default_angle));
+
+ // Second recursive call
+ c_curve(x, y, length, angle - default_angle, iteration - 1, points);
+ } else {
+ // Add the final segment to the points array
+ points.push(new THREE.Vector3(x, y, 0));
+ points.push(new THREE.Vector3(
+ x + length * Math.cos(toRadians(angle)),
+ y + length * Math.sin(toRadians(angle)),
+ 0
+ ));
+ }
+}
+*/
\ No newline at end of file
diff --git a/threejs/dodeahedron-fractal/style.css b/threejs/dodeahedron-fractal/style.css
new file mode 100644
index 00000000..6eb548eb
--- /dev/null
+++ b/threejs/dodeahedron-fractal/style.css
@@ -0,0 +1,19 @@
+*
+{
+ margin: 0;
+ padding: 0;
+}
+
+html,
+body
+{
+ overflow: hidden;
+}
+
+.webgl
+{
+ position: fixed;
+ top: 0;
+ left: 0;
+ outline: none;
+}
diff --git a/threejs/icosahedron-fractal/script.js b/threejs/icosahedron-fractal/script.js
index 4f477504..05201298 100644
--- a/threejs/icosahedron-fractal/script.js
+++ b/threejs/icosahedron-fractal/script.js
@@ -29,6 +29,7 @@ function init() {
// Icosahedron Geometry
const geometry = new THREE.IcosahedronGeometry(1);
+ //const geometry = new THREE.DodecahedronGeometry(1);
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x00ffff });
const edges = new THREE.EdgesGeometry(geometry);
@@ -43,7 +44,7 @@ function init() {
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
bloomPass.threshold = 0;
bloomPass.strength = 2; // Intensity of the bloom
- bloomPass.radius = 1;
+ bloomPass.radius = 0.9;
composer.addPass(bloomPass);
// Handle window resize
@@ -54,7 +55,9 @@ function animate() {
requestAnimationFrame(animate);
// Rotate the icosahedron
- scene.children[0].rotation.y += 0.01;
+ scene.children[0].rotation.y += 0.001;
+ scene.children[0].rotation.x -= 0.002;
+ scene.children[0].rotation.z += 0.002;
// Update fractal
updateFractal();