SCSS
/* Kaushan+Script, oregano, sail */
@import url('https://fonts.googleapis.com/css?family=Kaushan+Script');
html, body, .container {
height: 100%;
font-family: 'Kaushan Script','Sail', cursive;
}
body {
background: #e74;
overflow: hidden;
background-image: linear-gradient( to bottom, #190e14 ,#0d0d4b 30%, #c76075 80%, #e9b64b 95% );
background-image:
radial-gradient(circle at center bottom, #e9b64b ,#c76075 15%, #0d0d4b 75%, #190e14 90%);
}
div#beach,
canvas#canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
div#beach {
background-image: url(https://dl.dropbox.com/s/oe0oce2udq44bj5/beachsil2.png);
/* background-size: cover; */
background-position: bottom right;
background-size: 1700px;
background-repeat: no-repeat;
}
div#video {
position: absolute;
right: 243px;
bottom: 200px;
}
div#video iframe {
width: 255px;
height: 155px;
}
#people {
position: absolute;
bottom: 65px;
left: 40px;
width: 140px;
}
#car {
position: absolute;
bottom: 46px;
left: 180px;
width: 230px;
}
div#sea {
background-color: blue;
height: 85px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
background-image:
radial-gradient(circle at center top, #23485a, #0d0246);
}
.merrywrap{
position: absolute;
right: 0px;
left: 0px;
bottom: 0px;
top: 0px;
background-color: #d44;
transition: background-color .5s ease;
}
.giftbox{
position: absolute;
width:300px;
height:200px;
left:50%;
margin-left: -150px;
bottom: 40px;
z-index:10;
&>div{
background: #34495e;
position: absolute;
&:after,&:before{
position: absolute;
content:"";
top: 0;
}
}
&:after{
position: absolute;
color:#fff;
width:100%;
content:"Click Me!";
left: 0;
bottom: 0;
font-size: 24px;
text-align: center;
transform:rotate(-20deg);
transform-origin:0 0;
}
.cover{
width:100%;
top: 0;
left: 0;
height:25%;
z-index:2;
&:before{
position: absolute;
height:100%;
left: 50%;
width:50px; transform:translateX(-50%);
background:#fdc56d;
}
&>div{
position: absolute;
width:50px;
height:50px;
left:50%;
top:-50px; transform:translateX(-50%);
&:before,&:after{
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
content:"";
box-shadow:inset 0 0 0 15px #fdc56d;
border-radius:30px;
transform-origin:50% 100%;
}
&:before{
transform:translateX(-45%) skewY(40deg);
}
&:after{ transform:translateX(45%) skewY(-40deg);
}
}
}
.box{
right:5%;
left:5%;
height:80%;
bottom: 0;
&:before{
width:50px;
height:100%;
left:50%;
transform:translateX(-50%);
background:#fdc56d;
}
&:after{
width:100%;
height:30px;
background:rgba(0,0,0,0.2);
}
}
}
.icons{
position:absolute;
left: 10px;
/*top:50%;
width: 100%;*/
height: auto;
transform:translateY(10px) rotate(-20deg);
.row{
width:100%;
text-align: center;
span{
color: #e5e5e5;
text-shadow: 4px 4px 0 rgba(96, 125, 139, 0.4);
font-size: 50px;
display: inline-block;
opacity:0;
transition: transform 0.5s ease-in, opacity 0.7s;
}
}
}
.step-1{
.giftbox{
animation:wobble 0.5s linear infinite forwards;
}
.cover{
animation:wobble 0.5s linear infinite 0.1s forwards;
}
.icons .row span{
opacity:1;
}
}
.step-2 .giftbox:after{
opacity:0;
}
.step-3 .giftbox,
.step-4 .giftbox{
opacity: 0;
z-index:1;
&:after{
opacity:0;
}
}
.step-2{
.giftbox{
.cover{
animation:flyUp 0.4s ease-in forwards;
}
.box{
animation:flyDown 0.2s ease-in 0.05s forwards;
}
}
}
@keyframes wobble{
25%{
transform:rotate(4deg);
}
75%{
transform:rotate(-2deg);
}
}
@keyframes flyUp{
75%{
opacity:1;
}
100%{
transform:translateY(-1000px) rotate(20deg);
opacity:0;
}
}
@keyframes flyDown{
75%{
opacity:1;
}
100%{
transform:translateY(100%);
opacity:0;
}
}
.step-1 .icons .row span{
opacity:0;
}
.step-1 .icons .row span:first-child {
transform: translateY(700%) translateX(600%);
}
.step-1 .icons .row span:nth-child(2) {
transform: translateY(700%) translateX(500%);
}
.step-1 .icons .row span:nth-child(3) {
transform: translateY(700%) translateX(400%);
}
.step-1 .icons .row span:nth-child(4) {
transform: translateY(700%) translateX(300%);
}
.step-1 .icons .row span:nth-child(5) {
transform: translateY(700%) translateX(200%);
}
.step-1 .icons .row span:nth-child(6) {
transform: translateY(700%) translateX(100%);
}
.step-1 .icons .row span:nth-child(7) {
transform: translateY(700%) translateX(0);
}
.step-1 .icons .row span:nth-child(8) {
transform: translateY(700%) translateX(-100%);
}
.step-1 .icons .row span:nth-child(9) {
transform: translateY(700%) translateX(-200%);
}
.step-1 .icons .row span:nth-child(10) {
transform: translateY(700%) translateX(-300%);
}
.step-1 .icons .row span:nth-child(11) {
transform: translateY(700%) translateX(-400%);
}
.step-1 .icons .row span:nth-child(12) {
transform: translateY(700%) translateX(-500%);
}
.step-1 .icons .row span:nth-child(13) {
transform: translateY(700%) translateX(-600%);
}
.step-2 .icons .row span:nth-child(2) {
-webkit-transition-delay: 0.1s;
transition-delay: 0.1s;
}
.step-2 .icons .row span:nth-child(3) {
-webkit-transition-delay: 0.15s;
transition-delay: 0.15s;
}
.step-2 .icons .row span:nth-child(4) {
-webkit-transition-delay: 0.2s;
transition-delay: 0.2s;
}
.step-2 .icons .row span:nth-child(5) {
-webkit-transition-delay: 0.25s;
transition-delay: 0.25s;
}
.step-2 .icons .row span:nth-child(6) {
-webkit-transition-delay: 0.3s;
transition-delay: 0.3s;
}
.step-2 .icons .row span:nth-child(7) {
-webkit-transition-delay: 0.35s;
transition-delay: 0.35s;
}
.step-2 .icons .row span:nth-child(8) {
-webkit-transition-delay: 0.4s;
transition-delay: 0.4s;
}
.step-2 .icons .row span:nth-child(9) {
-webkit-transition-delay: 0.45s;
transition-delay: 0.45s;
}
.step-2 .icons .row span:nth-child(10) {
-webkit-transition-delay: 0.5s;
transition-delay: 0.5s;
}
.step-2 .icons .row span:nth-child(11) {
-webkit-transition-delay: 0.55s;
transition-delay: 0.55s;
}
.step-2 .icons .row span:nth-child(12) {
-webkit-transition-delay: 0.6s;
transition-delay: 0.6s;
}
.step-2 .icons .row span:nth-child(13) {
-webkit-transition-delay: 0.65s;
transition-delay: 0.65s;
}
.step-2 .icons span,.step-3 .icons span,.step-4 .icons span {
opacity: 1;
transition-timing-function: cubic-bezier(0.000, 0.000, 0.200, 0.910);
}
.step-4 .icons .row span,.step-3 .icons .row span {
/*animation: wobble 0.6s linear infinite forwards;*/
color: #c6e2ff;
animation: neon .08s ease-in-out infinite alternate;
}
.step-4 .icons .row span:nth-child(even),.step-3 .icons .row span:nth-child(even) {
animation-duration: 0.7s;
}
@keyframes neon {
from {
text-shadow:
0 0 6px rgba(202,228,225,0.92),
0 0 30px rgba(202,228,225,0.34),
0 0 12px rgba(30,132,242,0.52),
0 0 21px rgba(30,132,242,0.92),
0 0 34px rgba(30,132,242,0.78),
0 0 54px rgba(30,132,242,0.92);
}
to {
text-shadow:
0 0 6px rgba(202,228,225,0.98),
0 0 30px rgba(202,228,225,0.42),
0 0 12px rgba(30,132,242,0.58),
0 0 22px rgba(30,132,242,0.84),
0 0 38px rgba(30,132,242,0.88),
0 0 60px rgba(30,132,242,1);
}
}
.moon {
position: absolute;
top: 10%;
right: 200px;
width: 100px;
height: 100px;
border-radius: 50%;
background: #ddd;
box-shadow: inset 20px -10px 0 0 #b9b9b9;
}
.moon .crater1 {
position: absolute;
width: 30px;
height: 30px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -3px 1.5px 0 0 #aaa;
top: 20px;
right: 20px;
}
.moon .crater2 {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -1px 0.5px 0 0 #aaa;
top: 45px;
right: 50px;
}
.moon .crater3 {
position: absolute;
width: 15px;
height: 15px;
border-radius: 50%;
background: #bbb;
box-shadow: inset -1.5px 0.75px 0 0 #aaa;
top: 60px;
right: 25px;
}
@media (min-width: 1000px) {
.icons { left: 30px; }
.icons .row span { font-size: 56px; }
#people {
left: 80px;
bottom: 70px;
width: 160px;
}
div#beach {
background-size: 2000px;
}
div#video {
right: 290px;
bottom: 235px;
}
div#video iframe {
width: 295px;
height: 185px;
}
.moon {
right: 230px;
}
}
JAVASCRIPT
/*
Everybody say Happy Birthday! This gift is a compound of various pens plus some other things I added
- gift
https://codepen.io/ElaineXu/pen/EWvGWX
- neon
https://codepen.io/markheggan/pen/LjrVYN
- fireworks
https://codepen.io/chuongdang/pen/yzpDG
- moon
https://codepen.io/agelber/pen/sjIKp
*/
window.requestAnimFrame = ( function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ) {
window.setTimeout( callback, 1000 / 60 );
};
})();
// now we will setup our basic variables for the demo
var canvas = document.getElementById( 'canvas' ),
ctx = canvas.getContext( '2d' ),
// full screen dimensions
cw = window.innerWidth,
ch = window.innerHeight,
// firework collection
fireworks = [],
// particle collection
particles = [],
// starting hue
hue = 120,
// when launching fireworks with a click, too many get launched at once without a limiter, one launch per 5 loop ticks
limiterTotal = 5,
limiterTick = 0,
// this will time the auto launches of fireworks, one launch per 80 loop ticks
timerTotal = 80,
timerTick = 0,
mousedown = false,
// mouse x coordinate,
mx,
// mouse y coordinate
my;
// set canvas dimensions
canvas.width = cw;
canvas.height = ch;
// now we are going to setup our function placeholders for the entire demo
// get a random number within a range
function random( min, max ) {
return Math.random() * ( max - min ) + min;
}
// calculate the distance between two points
function calculateDistance( p1x, p1y, p2x, p2y ) {
var xDistance = p1x - p2x,
yDistance = p1y - p2y;
return Math.sqrt( Math.pow( xDistance, 2 ) + Math.pow( yDistance, 2 ) );
}
// create firework
function Firework( sx, sy, tx, ty ) {
// actual coordinates
this.x = sx;
this.y = sy;
// starting coordinates
this.sx = sx;
this.sy = sy;
// target coordinates
this.tx = tx;
this.ty = ty;
// distance from starting point to target
this.distanceToTarget = calculateDistance( sx, sy, tx, ty );
this.distanceTraveled = 0;
// track the past coordinates of each firework to create a trail effect, increase the coordinate count to create more prominent trails
this.coordinates = [];
this.coordinateCount = 3;
// populate initial coordinate collection with the current coordinates
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
this.angle = Math.atan2( ty - sy, tx - sx );
this.speed = 2;
this.acceleration = 1.05;
this.brightness = random( 50, 70 );
// circle target indicator radius
this.targetRadius = 1;
}
// update firework
Firework.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// cycle the circle target indicator radius
if( this.targetRadius < 8 ) {
this.targetRadius += 0.3;
} else {
this.targetRadius = 1;
}
// speed up the firework
this.speed *= this.acceleration;
// get the current velocities based on angle and speed
var vx = Math.cos( this.angle ) * this.speed,
vy = Math.sin( this.angle ) * this.speed;
// how far will the firework have traveled with velocities applied?
this.distanceTraveled = calculateDistance( this.sx, this.sy, this.x + vx, this.y + vy );
// if the distance traveled, including velocities, is greater than the initial distance to the target, then the target has been reached
if( this.distanceTraveled >= this.distanceToTarget ) {
createParticles( this.tx, this.ty );
// remove the firework, use the index passed into the update function to determine which to remove
fireworks.splice( index, 1 );
} else {
// target not reached, keep traveling
this.x += vx;
this.y += vy;
}
}
// draw firework
Firework.prototype.draw = function() {
ctx.beginPath();
// move to the last tracked coordinate in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1][ 0 ], this.coordinates[ this.coordinates.length - 1][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsl(' + hue + ', 100%, ' + this.brightness + '%)';
ctx.stroke();
ctx.beginPath();
// draw the target for this firework with a pulsing circle
ctx.arc( this.tx, this.ty, this.targetRadius, 0, Math.PI * 2 );
ctx.stroke();
}
// create particle
function Particle( x, y ) {
this.x = x;
this.y = y;
// track the past coordinates of each particle to create a trail effect, increase the coordinate count to create more prominent trails
this.coordinates = [];
this.coordinateCount = 5;
while( this.coordinateCount-- ) {
this.coordinates.push( [ this.x, this.y ] );
}
// set a random angle in all possible directions, in radians
this.angle = random( 0, Math.PI * 2 );
this.speed = random( 1, 10 );
// friction will slow the particle down
this.friction = 0.95;
// gravity will be applied and pull the particle down
this.gravity = 1;
// set the hue to a random number +-20 of the overall hue variable
this.hue = random( hue - 20, hue + 20 );
this.brightness = random( 50, 80 );
this.alpha = 1;
// set how fast the particle fades out
this.decay = random( 0.015, 0.03 );
}
// update particle
Particle.prototype.update = function( index ) {
// remove last item in coordinates array
this.coordinates.pop();
// add current coordinates to the start of the array
this.coordinates.unshift( [ this.x, this.y ] );
// slow down the particle
this.speed *= this.friction;
// apply velocity
this.x += Math.cos( this.angle ) * this.speed;
this.y += Math.sin( this.angle ) * this.speed + this.gravity;
// fade out the particle
this.alpha -= this.decay;
// remove the particle once the alpha is low enough, based on the passed in index
if( this.alpha <= this.decay ) {
particles.splice( index, 1 );
}
}
// draw particle
Particle.prototype.draw = function() {
ctx. beginPath();
// move to the last tracked coordinates in the set, then draw a line to the current x and y
ctx.moveTo( this.coordinates[ this.coordinates.length - 1 ][ 0 ], this.coordinates[ this.coordinates.length - 1 ][ 1 ] );
ctx.lineTo( this.x, this.y );
ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
ctx.stroke();
}
// create particle group/explosion
function createParticles( x, y ) {
// increase the particle count for a bigger explosion, beware of the canvas performance hit with the increased particles though
var particleCount = 30;
while( particleCount-- ) {
particles.push( new Particle( x, y ) );
}
}
// main demo loop
function loop() {
// this function will run endlessly with requestAnimationFrame
requestAnimFrame( loop );
// increase the hue to get different colored fireworks over time
hue += 0.5;
// normally, clearRect() would be used to clear the canvas
// we want to create a trailing effect though
// setting the composite operation to destination-out will allow us to clear the canvas at a specific opacity, rather than wiping it entirely
ctx.globalCompositeOperation = 'destination-out';
// decrease the alpha property to create more prominent trails
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect( 0, 0, cw, ch );
// change the composite operation back to our main mode
// lighter creates bright highlight points as the fireworks and particles overlap each other
ctx.globalCompositeOperation = 'lighter';
// loop over each firework, draw it, update it
var i = fireworks.length;
while( i-- ) {
fireworks[ i ].draw();
fireworks[ i ].update( i );
}
// loop over each particle, draw it, update it
var i = particles.length;
while( i-- ) {
particles[ i ].draw();
particles[ i ].update( i );
}
// launch fireworks automatically to random coordinates, when the mouse isn't down
if( timerTick >= timerTotal ) {
if( !mousedown ) {
// start the firework at the bottom middle of the screen, then set the random target coordinates, the random y coordinates will be set within the range of the top half of the screen
fireworks.push( new Firework( cw / 2, ch, random( 0, cw ), random( 0, ch / 2 ) ) );
timerTick = 0;
}
} else {
timerTick++;
}
// limit the rate at which fireworks get launched when mouse is down
if( limiterTick >= limiterTotal ) {
if( mousedown ) {
// start the firework at the bottom middle of the screen, then set the current mouse coordinates as the target
fireworks.push( new Firework( cw / 2, ch, mx, my ) );
limiterTick = 0;
}
} else {
limiterTick++;
}
}
window.onload=function(){
var merrywrap=document.getElementById("merrywrap");
var box=merrywrap.getElementsByClassName("giftbox")[0];
var step=1;
var stepMinutes=[2000,2000,1000,1000];
function init(){
box.addEventListener("click",openBox,false);
}
function stepClass(step){
merrywrap.className='merrywrap';
merrywrap.className='merrywrap step-'+step;
}
function openBox(){
if(step===1){
box.removeEventListener("click",openBox,false);
}
stepClass(step);
if(step===3){
}
if(step===4){
reveal();
return;
}
setTimeout(openBox,stepMinutes[step-1]);
step++;
}
init();
}
function reveal() {
document.querySelector('.merrywrap').style.backgroundColor = 'transparent';
loop();
var w, h;
if(window.innerWidth >= 1000) {
w = 295; h = 185;
}
else {
w = 255; h = 155;
}
var ifrm = document.createElement("iframe");
ifrm.setAttribute("src", "https://www.youtube.com/embed/KDxJlW6cxRk?controls=0&loop=1&autoplay=1");
//ifrm.style.width = `${w}px`;
//ifrm.style.height = `${h}px`;
ifrm.style.border = 'none';
document.querySelector('#video').appendChild(ifrm);
}