Custom Code Experiment •
Fractal SVG
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>Fractal SVG (MouseOver Effect)</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0a0a1a;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
font-family: 'Segoe UI', 'Monaco', monospace;
}
/* fractal container fills viewport with immersive bg */
.fractal-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
background: #03030c;
cursor: crosshair;
}
svg {
width: 100%;
height: 100%;
display: block;
filter: drop-shadow(0 0 6px rgba(0,0,0,0.4));
}
/* floating UI – minimal & elegant */
.info {
position: fixed;
bottom: 20px;
left: 20px;
background: rgba(15, 15, 30, 0.75);
backdrop-filter: blur(8px);
border-radius: 2rem;
padding: 8px 20px;
color: #ffe1aa;
font-size: 0.85rem;
font-weight: 500;
font-family: monospace;
letter-spacing: 1px;
border-left: 3px solid #ffcc77;
z-index: 10;
pointer-events: none;
box-shadow: 0 4px 18px rgba(0,0,0,0.4);
}
.badge {
position: fixed;
bottom: 20px;
right: 20px;
background: rgba(0,0,0,0.6);
backdrop-filter: blur(4px);
padding: 5px 14px;
border-radius: 40px;
font-size: 0.7rem;
color: #ccb87c;
font-family: monospace;
pointer-events: none;
z-index: 10;
}
.info span {
color: #ffdf99;
font-weight: bold;
animation: softPulse 2s infinite alternate;
}
@keyframes softPulse {
0% { text-shadow: 0 0 0px #ffdf99; opacity: 0.8; }
100% { text-shadow: 0 0 4px #ffbb44; opacity: 1; }
}
/* subtle overlay effect while hovering */
.fractal-bg:hover svg {
filter: drop-shadow(0 0 12px rgba(255,200,100,0.2));
transition: filter 0.2s ease;
}
</style>
</head>
<body>
<div class="fractal-bg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid slice">
<defs>
<!-- glowing gradients for depth -->
<radialGradient id="glowGold" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#ffd966" stop-opacity="0.9"/>
<stop offset="80%" stop-color="#cc9933" stop-opacity="0.3"/>
<stop offset="100%" stop-color="#442200" stop-opacity="0"/>
</radialGradient>
<linearGradient id="metalDark" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2a2418"/>
<stop offset="100%" stop-color="#0e0b07"/>
</linearGradient>
<filter id="glowEffect" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
<feMerge>
<feMergeNode in="offsetblur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- pattern for micro fill in deep space -->
<pattern id="stardust" patternUnits="userSpaceOnUse" width="40" height="40">
<circle cx="5" cy="8" r="0.8" fill="#ffdd99" opacity="0.5"/>
<circle cx="28" cy="22" r="0.5" fill="#ffbb77" opacity="0.6"/>
<circle cx="12" cy="35" r="0.6" fill="#ffcc88"/>
<circle cx="35" cy="12" r="0.4" fill="#ffe0aa"/>
</pattern>
</defs>
<!-- background starry canvas -->
<rect width="100%" height="100%" fill="url(#stardust)" opacity="0.3"/>
<rect width="100%" height="100%" fill="url(#metalDark)" opacity="0.85"/>
<!-- fractal groups: will be populated recursively via JS -->
<g id="fractalRoot" stroke-linecap="round" stroke-linejoin="round"></g>
<!-- decorative floating orbs (ambient) -->
<circle cx="15%" cy="20%" r="45" fill="url(#glowGold)" opacity="0.2">
<animate attributeName="opacity" values="0.1;0.3;0.1" dur="8s" repeatCount="indefinite"/>
</circle>
<circle cx="85%" cy="75%" r="70" fill="url(#glowGold)" opacity="0.15">
<animate attributeName="r" values="70;85;70" dur="12s" repeatCount="indefinite"/>
</circle>
</svg>
</div>
<div class="badge">
🔺 recursive depth 5 • mouse morph 🌀
</div>
<script>
(function(){
// ---------- ADVANCED FRACTAL SVG ENGINE ----------
// builds a recursive Sierpinski triangle / tetrahedral fractal variant
// with hover effect: colors shift + subtle local transforms
const svgNS = "http://www.w3.org/2000/svg";
const rootGroup = document.getElementById("fractalRoot");
if (!rootGroup) return;
// fractal parameters
const WIDTH = 1200;
const HEIGHT = 800;
const MAX_DEPTH = 5; // complexity: 5 levels = 243 triangles (dense)
let currentDepth = MAX_DEPTH;
// color palettes (rich, advanced metallic / neon)
const PALETTE_DEFAULT = [
"#ffbe76", "#f6ae72", "#e09d5e", "#c2814a", "#a26338", "#7e4a2a", "#5a3520", "#3e2618"
];
const PALETTE_HOVER = [
"#9b5de5", "#f15fbb", "#fee440", "#00bbf9", "#00f5d4", "#ff006e", "#fb8b67", "#ca7df9"
];
let hoverActive = false;
let currentPalette = PALETTE_DEFAULT;
// store generated fractal elements for efficient hover update
let fractalElements = []; // each: { element, baseFill, originalTransform, depth }
// --- recursive fractal: Sierpinski triangle (vertex-based) with beautiful subdivisions
// we create triangles at each depth, filled with gradient-like solid colors based on depth & position
function generateSierpinski(p1, p2, p3, depth, maxDepth, group) {
if (depth > maxDepth) return;
// compute midpoints for subdivision
const mid12 = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };
const mid23 = { x: (p2.x + p3.x) / 2, y: (p2.y + p3.y) / 2 };
const mid31 = { x: (p3.x + p1.x) / 2, y: (p3.y + p1.y) / 2 };
// draw main triangle at this depth (except at deepest level we draw all)
// but classic sierpinski: draw only the central inverted triangle as "hole" and recurse on corners
// instead we draw the corner triangles recursively, and the central triangle is omitted (hole)
// to create a more intricate lace-like pattern, we actually fill the corner triangles and leave center empty.
// However for visual richness we will fill all three corner triangles and also add decorative edges.
// fill corner triangles (with colors)
const cornerTriangles = [
{ points: [p1, mid12, mid31], depthOffset: 0 },
{ points: [p2, mid12, mid23], depthOffset: 1 },
{ points: [p3, mid23, mid31], depthOffset: 2 }
];
cornerTriangles.forEach((tri, idx) => {
const fillColor = getColorForDepth(depth, idx, tri.points[0].x, tri.points[0].y);
const trianglePoly = document.createElementNS(svgNS, "polygon");
const pointsStr = tri.points.map(p => `${p.x},${p.y}`).join(" ");
trianglePoly.setAttribute("points", pointsStr);
trianglePoly.setAttribute("fill", fillColor);
trianglePoly.setAttribute("stroke", "#f0cf8a");
trianglePoly.setAttribute("stroke-width", depth === 0 ? "1.2" : "0.55");
trianglePoly.setAttribute("stroke-opacity", "0.65");
trianglePoly.setAttribute("class", "fractal-triangle");
// add slight glow on edges
trianglePoly.setAttribute("filter", depth <= 2 ? "url(#glowEffect)" : "");
group.appendChild(trianglePoly);
// store for hover effects
fractalElements.push({
element: trianglePoly,
baseFill: fillColor,
depth: depth,
originalStroke: "#f0cf8a",
idx: idx
});
// recursive call for deeper levels
generateSierpinski(tri.points[0], tri.points[1], tri.points[2], depth + 1, maxDepth, group);
});
// optional: draw decorative central small shape (inverted star) only at certain depths
if (depth <= maxDepth - 2) {
const centerPoly = document.createElementNS(svgNS, "polygon");
const centerPoints = [mid12, mid23, mid31];
const pointsC = centerPoints.map(p => `${p.x},${p.y}`).join(" ");
centerPoly.setAttribute("points", pointsC);
centerPoly.setAttribute("fill", "none");
centerPoly.setAttribute("stroke", "#ffd58c");
centerPoly.setAttribute("stroke-width", "0.8");
centerPoly.setAttribute("stroke-dasharray", "4 2");
centerPoly.setAttribute("opacity", "0.5");
group.appendChild(centerPoly);
fractalElements.push({
element: centerPoly,
baseFill: "none",
depth: depth,
originalStroke: "#ffd58c",
isEdge: true
});
}
}
// advanced color mapping: based on depth, position (x), and hover state
function getColorForDepth(depth, subIdx, x, y) {
if (hoverActive) {
// psychedelic shifting: use palette hover + modulate by position
const hueShift = ((x * 0.003 + y * 0.002) * 20 + depth * 15 + subIdx * 40) % 360;
// pick from hover palette with rotation
const pal = PALETTE_HOVER;
const idx = (Math.floor(hueShift / 45) + depth * 2 + subIdx) % pal.length;
return pal[idx];
} else {
// default: warm gold / ember fractal
const baseIdx = (depth * 2 + subIdx) % PALETTE_DEFAULT.length;
let col = PALETTE_DEFAULT[baseIdx];
// vary brightness with x,y to create organic variation
const brightFactor = 0.7 + (Math.sin(x * 0.02 + y * 0.015) * 0.2);
// color adjustment (lighten/darken via simple rgb mix)
return adjustColorBrightness(col, brightFactor);
}
}
function adjustColorBrightness(hex, factor) {
// simple helper to make color richer
let r = parseInt(hex.slice(1,3), 16);
let g = parseInt(hex.slice(3,5), 16);
let b = parseInt(hex.slice(5,7), 16);
r = Math.min(255, Math.floor(r * factor));
g = Math.min(255, Math.floor(g * factor));
b = Math.min(255, Math.floor(b * factor));
return `rgb(${r}, ${g}, ${b})`;
}
// function to rebuild fractal (full generation)
function buildFractal(depthLevel) {
// clear previous
while (rootGroup.firstChild) {
rootGroup.removeChild(rootGroup.firstChild);
}
fractalElements = [];
// Define three main vertices of the big Sierpinski triangle (centered & majestic)
// Use viewBox 1200x800, create isosceles triangle covering most area.
const top = { x: 600, y: 80 };
const left = { x: 180, y: 720 };
const right = { x: 1020, y: 720 };
// recursive generation
generateSierpinski(top, left, right, 0, depthLevel, rootGroup);
// extra embellishment: fractal dust particles (tiny dots) inside deepest triangles
addFractalDust(rootGroup);
}
// add delicate particle system for extra 'advanced fractal' look
function addFractalDust(group) {
for (let i = 0; i < 340; i++) {
let x = 150 + Math.random() * 900;
let y = 80 + Math.random() * 680;
// only place inside plausible area
let radius = 0.9 + Math.random() * 2.2;
let dot = document.createElementNS(svgNS, "circle");
dot.setAttribute("cx", x);
dot.setAttribute("cy", y);
dot.setAttribute("r", radius);
dot.setAttribute("fill", `rgba(255, 210, 130, ${0.3 + Math.random() * 0.5})`);
dot.setAttribute("class", "dust-particle");
group.appendChild(dot);
fractalElements.push({ element: dot, isDust: true, baseOpacity: 0.3 + Math.random() * 0.5 });
}
}
// ---------- HOVER EFFECT: dynamic color morph & tiny rotations ----------
function applyHoverEffect(isHover) {
hoverActive = isHover;
// update all triangle colors based on new palette
fractalElements.forEach(item => {
if (item.element.tagName === "polygon") {
const depth = item.depth;
const subIdx = item.idx !== undefined ? item.idx : 0;
// get bounding box center for positional color variation
let bbox;
try {
bbox = item.element.getBBox();
} catch(e) { bbox = { x: 300, y: 300 }; }
const centerX = bbox.x + bbox.width/2;
const centerY = bbox.y + bbox.height/2;
const newFill = getColorForDepth(depth, subIdx, centerX, centerY);
item.element.setAttribute("fill", newFill);
// stroke magic: on hover, strokes become neon
if (isHover) {
item.element.setAttribute("stroke", "#ffdd77");
item.element.setAttribute("stroke-width", "1.1");
item.element.setAttribute("stroke-opacity", "0.95");
// subtle transform scale per triangle (local)
if (depth <= 2) {
item.element.setAttribute("transform", "scale(1.01) translate(-0.5%, -0.5%)");
}
} else {
item.element.setAttribute("stroke", "#f0cf8a");
item.element.setAttribute("stroke-width", depth === 0 ? "1.2" : "0.55");
item.element.setAttribute("stroke-opacity", "0.65");
item.element.removeAttribute("transform");
}
}
else if (item.element.tagName === "polyline" || item.element.tagName === "line") {
// optional edge handling
if (isHover) {
item.element.setAttribute("stroke", "#ffcc88");
item.element.setAttribute("stroke-width", "1.4");
} else {
item.element.setAttribute("stroke", "#ffd58c");
item.element.setAttribute("stroke-width", "0.8");
}
}
else if (item.element.classList && item.element.classList.contains("dust-particle")) {
// dust particles react: increase opacity and glow on hover
const newOpacity = isHover ? 0.85 : (item.baseOpacity || 0.4);
item.element.setAttribute("fill", isHover ? `rgba(255, 220, 100, ${newOpacity})` : `rgba(255, 210, 130, ${newOpacity})`);
if (isHover) {
let rad = parseFloat(item.element.getAttribute("r")) || 1.2;
item.element.setAttribute("r", rad * 1.6);
} else {
let rad = parseFloat(item.element.getAttribute("originalR")) || 1.2;
if (!item.element.getAttribute("originalR")) {
let orig = parseFloat(item.element.getAttribute("r")) || 1.2;
item.element.setAttribute("originalR", orig);
rad = orig;
} else {
rad = parseFloat(item.element.getAttribute("originalR"));
}
item.element.setAttribute("r", rad);
}
}
});
// add extra floating animated effect: rotate the entire root slightly on hover? (subtle)
if (isHover) {
rootGroup.setAttribute("transform", "rotate(0.2, 600, 400)");
} else {
rootGroup.removeAttribute("transform");
}
}
// ---------- Mouse tracking + hover state ----------
const container = document.querySelector(".fractal-bg");
let hoverTimeout = null;
function onMouseMoveWithin(event) {
if (!hoverActive) {
applyHoverEffect(true);
// also shift color palette dynamically based on mouse position for extra 'advanced'
updateDynamicColorShift(event);
} else {
updateDynamicColorShift(event);
}
// reset debounce for leaving
if (hoverTimeout) clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(() => {
// not leaving yet, but keep fresh
}, 50);
}
function updateDynamicColorShift(event) {
if (!hoverActive) return;
// Extra interactivity: color shift based on mouse X/Y position (RGB modulation)
const rect = container.getBoundingClientRect();
const mouseNormX = (event.clientX - rect.left) / rect.width;
const mouseNormY = (event.clientY - rect.top) / rect.height;
// apply subtle 'chromatic aberration' to strokes/fills on the fly
fractalElements.forEach(item => {
if (item.element.tagName === "polygon" && item.depth !== undefined) {
const depth = item.depth;
let hueOffset = Math.floor(mouseNormX * 8 + mouseNormY * 5) % PALETTE_HOVER.length;
let colIndex = (depth + hueOffset) % PALETTE_HOVER.length;
let newCol = PALETTE_HOVER[colIndex];
// also modulate brightness
let bright = 0.7 + (mouseNormX * 0.5);
let finalCol = adjustColorBrightness(newCol, bright);
item.element.setAttribute("fill", finalCol);
// additional warp: tiny rotation offset for inner triangles
if (depth <= 2) {
let rotAngle = (mouseNormX - 0.5) * 2.5;
item.element.setAttribute("transform", `rotate(${rotAngle}, 0, 0) scale(1.01)`);
}
}
});
}
function onMouseLeaveContainer() {
if (hoverActive) {
applyHoverEffect(false);
// reset any dynamic transforms on polygons
fractalElements.forEach(item => {
if (item.element.tagName === "polygon" && item.depth !== undefined && item.depth <= 2) {
item.element.removeAttribute("transform");
}
});
if (hoverTimeout) clearTimeout(hoverTimeout);
}
}
// rebuild fractal on window load (ensures smooth)
function init() {
buildFractal(MAX_DEPTH);
// attach hover events
container.addEventListener("mousemove", onMouseMoveWithin);
container.addEventListener("mouseleave", onMouseLeaveContainer);
// also add mousemove throttling is fine
// optional: add window resize adaptation? we keep viewBox fixed so fractal stays centered
// but for extra responsiveness, we might rebuild on orientation? not mandatory.
// little extra: add animated legend to UI using pseudo effect
const modeSpan = document.querySelector(".info span");
if (modeSpan) {
setInterval(() => {
if (hoverActive) {
modeSpan.textContent = "🌀 FRACTAL WARP ACTIVE 🌀";
} else {
modeSpan.textContent = "SIERPINSKI FRACTAL TETRA";
}
}, 300);
}
}
// also export a regeneration on demand? no needed
init();
})();
</script>
</body>
</html>