Gave myself an hour to put together something for the geminid meteor shower. Here it is!
Dynamically animated and positioned stars + shooters w/ CSS variables.
Drop shadow for the house on the hill.
Enjoy!
- const inRange = (max, min) => Math.floor(Math.random() * (max - min + 1)) + min | |
- const amount = 30 | |
- for (let g = 0; g < amount; g++) | |
- let angle = inRange(45, 95) | |
- let speed = inRange(8, 20) | |
- let delay = inRange(1, 25) | |
- let x = inRange(0, 80) | |
- let y = inRange(0, 25) | |
- let travel = inRange(10, 50) | |
- let trail = inRange(1, 5) | |
.geminid(style=`--angle: ${angle}; --speed: ${speed}; --delay: ${delay}; --x: ${x}; --y: ${y}; --travel: ${travel}; --trail: ${trail}`) | |
.geminid__trail | |
- for (let s = 0; s < 35; s++) | |
- let x = inRange(0, 100) | |
- let y = inRange(0, 100) | |
- let opacity = inRange(0, 100) | |
- let scale = inRange(0, 3) | |
.star(style=`--x: ${x}; --y: ${y}; --opacity: ${opacity / 100}; --scale: ${scale}`) | |
.hill | |
.house__wrap | |
.house | |
.house__house | |
.house__roof |
// NOT FOUND |
* | |
box-sizing border-box | |
body | |
background linear-gradient(160deg, rgb(20, 29, 48), rgb(35, 44, 74), rgb(62, 81, 118)) | |
min-height 100vh | |
.geminid | |
position absolute | |
top calc(var(--y) * 1vh) | |
left calc(var(--x) * 1vw) | |
animation shoot calc(var(--speed) * 1s) calc(var(--delay) * 1s) infinite linear both | |
&__trail | |
height 2px | |
width 25px | |
position absolute | |
background linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.85)) | |
border-radius 100% 25% 25% 100% | |
filter blur(1px) | |
transform-origin right | |
filter drop-shadow(0 0 5px #fafafa) | |
animation spark calc(var(--speed) * 1s) calc(var(--delay) * 1s) infinite linear both | |
@media(min-width 768px) | |
height 5px | |
width 50px | |
.star | |
border-radius 100% | |
height 1px | |
width 1px | |
position absolute | |
top calc(var(--y) * 1vh) | |
left calc(var(--x) * 1vw) | |
background #fafafa | |
opacity var(--opacity) | |
transform scale(var(--scale)) | |
@keyframes shoot | |
0% | |
transform rotate(calc(var(--angle) * 1deg)) | |
5%, 100% | |
transform rotate(calc(var(--angle) * 1deg)) translate(calc(var(--travel) * 1vw), 0) | |
@keyframes spark | |
0%, 5%, 100% | |
transform scaleX(0) | |
1%, 4% | |
transform scaleX(var(--trail)) | |
.hill | |
background #000 | |
height 20vh | |
width 75vw | |
max-width 400px | |
position absolute | |
bottom 0 | |
right 0 | |
border-radius 50% 0 0 0 / 100% 0 0 0 | |
.house__wrap | |
position absolute | |
bottom 100% | |
right 0 | |
filter drop-shadow(-50px -50px 100px white) | |
.house | |
height 150px | |
width 150px | |
&__house | |
position absolute | |
height 50% | |
width 75% | |
bottom 0 | |
right 0 | |
background #111 | |
&:after | |
content '' | |
background #fff9de | |
box-shadow 0 0 5px 0 #fff9de | |
position absolute | |
left 20% | |
top 20% | |
bottom 40% | |
width 20% | |
&__roof | |
position absolute | |
top 0 | |
right 0 | |
height 50% | |
width 100% | |
background #111 | |
$clip = polygon(0 100%, 35% 45%, 35% 0, 55% 0, 55% 25%, 100% 25%, 100% 100%) | |
-webkit-clip-path $clip | |
clip-path $clip |