.container
.container__item(style="--move-x: -1; --rotate: 90; --x: 10; --y: 60; --size: 30; --hue: 220;")
.container__item(style="--move-x: 1.6; --move-y: -2; --rotate: -45; --x: 75; --y: 20; --size: 50; --hue: 240;")
.container__item(style="--move-x: -3; --move-y: 1; --rotate: 360; --x: 75; --y: 80; --size: 40; --hue: 260;")
View Compiled
*
box-sizing border-box
body
min-height 100vh
font-weight bold
font-size 1.15rem
font-family sans-serif
text-align center
display grid
place-items center
background hsl(260, 50%, 50%)
overflow hidden
transform-style preserve-3d
perspective 50vmin
.container
height 135px
width 135px
background hsl(25, 100%, 80%)
display grid
place-content center
border-radius 50%
position relative
transition transform 0.1s
transform rotateY(calc(var(--ratio-x, 0) * 20deg)) rotateX(calc(var(--ratio-y, 0) * -20deg))
&:after
content ''
position absolute
top 50%
left 50%
height 200px
width 200px
border-radius 50%
background hsla(280, 50%, 80%, 0.5)
transform translate(-50%, -50%)
z-index -1
&__item
position absolute
top calc(var(--y, 0) * 1%)
left calc(var(--x, 0) * 1%)
height calc(var(--size, 20) * 1px)
width calc(var(--size, 20) * 1px)
background 'hsl(%s, 80%, 80%)' % var(--hue, 0)
transition transform 0.1s
transform translate(-50%, -50%) translate(calc(var(--move-x, 0) * var(--ratio-x, 0) * 100%), calc(var(--move-y, 0) * var(--ratio-y, 0) * 100%)) rotate(calc(var(--rotate, 0) * var(--ratio-x, 0) * 1deg))
View Compiled
import gsap from 'https://cdn.skypack.dev/gsap'
const CONTAINER = document.querySelector('.container')
const generateHandler = (element, proximity, bounds, cb) => ({x, y}) => {
const elementBounds = element.getBoundingClientRect()
const centerX = elementBounds.left + elementBounds.width / 2
const centerY = elementBounds.top + elementBounds.height / 2
const boundX = gsap.utils.mapRange(centerX - proximity, centerX + proximity, -bounds, bounds, x)
const boundY = gsap.utils.mapRange(centerY - proximity, centerY + proximity, -bounds, bounds, y)
cb(boundX, boundY)
}
const UPDATE = (x, y) => {
CONTAINER.style.setProperty('--ratio-x', Math.floor(gsap.utils.clamp(-100, 100, x)) / 100)
CONTAINER.style.setProperty('--ratio-y', Math.floor(gsap.utils.clamp(-100, 100, y)) / 100)
}
document.addEventListener('pointermove', generateHandler(document.body, 100, 100, UPDATE))
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.