canvas
.menu
button
.icon
span
span
span
label
| Amount
input(type='range', min="1", max="500", step="1", value="100", id="AMOUNT")
label
| Upper Velocity Bounds
input(type='range', min="1", max="50", step="1", value="20", id="UPPER_LIMIT")
label
| Lower Velocity Bounds
input(type='range', min="1", max="50", step="1", value="1", id="LOWER_LIMIT")
label
| Blur
input(type='range', min="0", max="10", step="1", value="2", id="BLUR")
View Compiled
:root
--blur 2
*
box-sizing border-box
html
body
font-family 'Arial', sans-serif
background #111
canvas
position fixed
height 100vh
width 100vw
filter blur(calc(var(--blur) * 1px))
input
cursor pointer
display block
label
margin-bottom 30px
&:last-of-type
margin-bottom 0
.menu
position absolute
top 0
left 0
color #fafafa
background rgba(0, 0, 0, 0.15)
display flex
flex-direction column
padding 30px
transform translate(-100%, 0)
transition transform .25s ease-out
&--open
transform translate(0, 0)
.icon
height 60%
width 60%
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
button
height 0px
width 0px
background 0
cursor pointer
border 0
background rgba(0, 0, 0, 0.15)
padding 0
margin 0
position absolute
left 100%
top 0
span
width 100%
height 20%
border-radius 4px
background white
display block
position absolute
top 0
transition transform .25s ease-out
&:nth-child(1)
transform-origin top left
&:nth-child(2)
top 40%
&:nth-child(3)
transform-origin top left
top 80%
.menu--open
span:nth-child(1)
transform translate(5px, 3px) rotate(45deg)
span:nth-child(2)
transform scaleX(0)
span:nth-child(3)
transform translate(2px, 0) rotate(-45deg)
View Compiled
const canvas = document.querySelector('canvas')
const context = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
requestAnimationFrame = requestAnimationFrame || webkitRequestAnimationFrame
const menu = document.querySelector('.menu')
const modify = e => {
OPTIONS[e.target.id] = parseInt(e.target.value, 10)
if (e.target.id === 'AMOUNT') {
context.clearRect(0, 0, canvas.width, canvas.height)
particles = genParticles()
}
if (e.target.id === 'BLUR') {
document.documentElement.style.setProperty('--blur', parseInt(e.target.value, 10))
}
}
menu.addEventListener('change', modify)
const button = document.querySelector('button')
const handleClick = e => menu.classList.toggle('menu--open')
button.addEventListener('click', handleClick)
const OPTIONS = {
AMOUNT: 100,
UPPER_LIMIT: 20,
LOWER_LIMIT: 1,
}
const UPPER_SIZE = 10
const LOWER_SIZE = 4
const doIt = () => Math.random() > 0.5
const update = p =>
doIt()
? Math.max(OPTIONS.LOWER_LIMIT, p - 1)
: Math.min(p + 1, OPTIONS.UPPER_LIMIT)
const reset = p => {
p.x = p.startX
p.y = p.startY
}
const floored = r => Math.floor(Math.random() * r)
const genParticles = () =>
new Array(OPTIONS.AMOUNT).fill().map(p => {
const size = floored(UPPER_SIZE) + LOWER_SIZE
const c = document.createElement('canvas')
const ctx = c.getContext('2d')
const r = (Math.PI / 180) * floored(360)
const color = `rgba(255,${100 +
Math.floor(Math.random() * 70)}, 0, ${Math.random()})`
const xDelayed = doIt()
const startX = xDelayed
? -(size + floored(canvas.width))
: floored(canvas.width * 0.25)
const startY = xDelayed
? size + floored(canvas.height * 0.25) + Math.floor(canvas.height * 0.75)
: canvas.height + size + floored(canvas.height)
c.height = size
c.width = size
context.globalCompositeOperation = 'multiply'
// ctx.filter = `blur(${Math.random() * size}px)`
ctx.translate(size / 2, size / 2)
ctx.rotate(r)
ctx.translate(-(size / 2), -(size / 2))
ctx.fillStyle = color
ctx.fillRect(0, 0, size, size)
return {
x: startX,
y: startY,
startY,
startX,
c,
r,
vx: floored(OPTIONS.UPPER_LIMIT / 4),
vy: floored(OPTIONS.UPPER_LIMIT / 4),
size,
}
})
let particles = genParticles()
let FRAME_COUNT = 0
const draw = () => {
if (
canvas.width !== window.innerWidth ||
canvas.height !== window.innerHeight
) {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
particles = genParticles()
}
// context.restore()
for (const particle of particles) {
context.clearRect(particle.x, particle.y, particle.size, particle.size)
FRAME_COUNT++
if (particle.y < canvas.height || particle.startX < 0)
particle.x += particle.vx
if (particle.x > 0 || particle.startY > canvas.height)
particle.y -= particle.vy
if (FRAME_COUNT % 11 === 0 && doIt()) particle.vx = update(particle.vx)
if (FRAME_COUNT % 13 === 0 && doIt()) particle.vy = update(particle.vy)
context.drawImage(particle.c, particle.x, particle.y)
if (particle.x > canvas.width || particle.y < -particle.size)
reset(particle)
}
requestAnimationFrame(draw)
}
requestAnimationFrame(draw)
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.