JSFiddle - React, Tailwind, and code Playground
by Craig Haywood
September 14, 2024
HTML
<!-- This was made for the codepen challege however is using a custom
made SVG which I have imported into the CSS using background-image.I have
another pen for the challenge using js only https://codepen.io/thomasbutler/pen/MWMVeoW
-->
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Raleway+Dots&display=swap"
rel="stylesheet">
</head>
<body>
<div id="fractal-container">
<div class="layer" id="layer1">
</div>
<div class="layer" id="layer2">
</div>
<div class="layer" id="layer3">
</div>
</div>
<div id="controls">
Feel like you are in a death spiral?<br/>We can help<br/><br/><img width="24" height="24" src="https://www.secondsplash.com/pointer.png"/>
</div>
CSS
body, html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
font-family: "Raleway Dots", sans-serif;
font-weight: 400;
font-style: normal;
background: linear-gradient(
90deg,#ff0000,#ff7f00,#ffff00,#7fff00,#00ff00,
#00ffff,#007fff,#0000ff,#7f00ff,#ff00ff
);
}
#fractal-container {
position: relative;
width: 100vw;
height: 100vh;
perspective: 1000px;
}
.layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("https://assets.codepen.io/11761718/LN13ya01.svg");
background-size: cover;
background-position: center;
opacity: 0.7;
mix-blend-mode: screen;
transition: transform 0.1s ease-out;
}
#layer1 { filter: hue-rotate(0deg); }
#layer2 { filter: hue-rotate(120deg); }
#layer3 { filter: hue-rotate(240deg); }
#controls {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 1);
padding: 15px;
border-radius: 15px;
display: flex;
align-items: center;
z-index: 1000;
color: white;
text-align: center;
font-weight: bold
}
input[type="range"] {
-webkit-appearance: none;
width: 150px;
height: 5px;
background: rgba(255, 255, 255, 0.3);
outline: none;
border-radius: 5px;
margin: 0 10px;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 15px;
height: 15px;
background: #00ffaa;
cursor: pointer;
border-radius: 50%;
}
input[type="range"]::-moz-range-thumb {
width: 15px;
height: 15px;
background: #00ffaa;
cursor: pointer;
border-radius: 50%;
}
label {
color: #00ffaa;
margin-right: 20px;
font-weight: 400;
font-style: normal;
text-shadow: 0 0 5px #00ffaa;
}
/* Media Queries */
@media (max-width: 1024px) {
#controls {
flex-direction: column;
align-items: stretch;
width: 90%;
max-width: 350px;
background: rgba(0, 0, 0, 0.8);
}
input[type="range"] {
width: 100%;
margin: 10px 0;
}
...
JavaScript
let zoomLevel = 1;
let animationSpeed = 1;
let distortionLevel = 0;
function init() {
window.addEventListener('resize', adjustForScreenSize);
adjustForScreenSize();
animate();
}
function updateZoom() {
zoomLevel = 1;
}
function updateSpeed() {
animationSpeed = 1;
}
function updateDistortion() {
distortionLevel = 0;
}
function handleMouseMove(e) {
const x = e.clientX / window.innerWidth - 0.5;
const y = e.clientY / window.innerHeight - 0.5;
rotateFractal(x, y);
}
function handleTouchMove(e) {
const touch = e.touches[0];
const x = touch.clientX / window.innerWidth - 0.5;
const y = touch.clientY / window.innerHeight - 0.5;
rotateFractal(x, y);
}
function rotateFractal(x, y) {
const container = document.getElementById('fractal-container');
container.style.transform = `rotateY(${x * 20}deg) rotateX(${-y * 20}deg)`;
}
function adjustForScreenSize() {
const container = document.getElementById('fractal-container');
const size = Math.max(window.innerWidth, window.innerHeight);
container.style.width = `${size}px`;
container.style.height = `${size}px`;
container.style.left = `${(window.innerWidth - size) / 2}px`;
container.style.top = `${(window.innerHeight - size) / 2}px`;
}
function animate() {
const layers = document.querySelectorAll('.layer');
const time = Date.now() * 0.001 * animationSpeed;
layers.forEach((layer, index) => {
const scale = zoomLevel * (1 + Math.sin(time + index) * 0.1);
const rotate = Math.sin(time * 0.5 + index) * 10;
const translateX = Math.sin(time * 0.7 + index) * distortionLevel;
const translateY = Math.cos(time * 0.7 + index) * distortionLevel;
layer.style.transform = `scale(${scale}) rotate(${rotate}deg) translate(${translateX}px, ${translateY}px)`;
});
requestAnimationFrame(animate);
}
window.addEventListener('load', init);