Skip to content

Instantly share code, notes, and snippets.

@mayerspitz
Created December 14, 2021 17:10
Show Gist options
  • Save mayerspitz/0b97a164624c38211fe6b5342105e963 to your computer and use it in GitHub Desktop.
Save mayerspitz/0b97a164624c38211fe6b5342105e963 to your computer and use it in GitHub Desktop.
Spotify Wrapped Animation using GSAP
<div class="container">
<div class="tube">
<h1 class="clone">Tastebreakers</h1>
</div>
<div class="final__wrap"></div>
<!-- Required Structure -->
<!-- <div class="tube">
<h1 class="line line1">Tastebreakers</h1>
<h1 class="line line2">Tastebreakers</h1>
<h1 class="line line3">Tastebreakers</h1>
</div>
<div class="final__wrap">
<h1 class="final">Tastebreakers</h1>
</div> -->
</div>
<a href="https://spotifywrapped.com/en/" target="_blank" class="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 558.43 167.49">
<title>Spotify Logo</title>
<g>
<path d="M88,1.28A83.74,83.74,0,1,0,171.74,85,83.75,83.75,0,0,0,88,1.28Zm38.4,120.78a5.22,5.22,0,0,1-7.18,1.74c-19.66-12-44.41-14.73-73.56-8.07a5.22,5.22,0,0,1-2.33-10.18c31.9-7.29,59.27-4.15,81.34,9.34A5.21,5.21,0,0,1,126.4,122.06Zm10.25-22.8a6.53,6.53,0,0,1-9,2.15c-22.51-13.83-56.82-17.84-83.45-9.76a6.53,6.53,0,1,1-3.79-12.49c30.41-9.23,68.22-4.76,94.07,11.12A6.53,6.53,0,0,1,136.65,99.26Zm.88-23.74c-27-16-71.52-17.51-97.29-9.69a7.83,7.83,0,0,1-4.54-15c29.58-9,78.75-7.24,109.83,11.21a7.83,7.83,0,0,1-8,13.47Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<g>
<g>
<path d="M232.09,78.59c-14.46-3.45-17-5.87-17-11,0-4.8,4.52-8,11.24-8,6.52,0,13,2.45,19.77,7.51a1,1,0,0,0,1.34-.22l7.06-10a1,1,0,0,0-.18-1.29A42.74,42.74,0,0,0,226.52,46C210.91,46,200,55.4,200,68.81c0,14.37,9.41,19.46,25.66,23.39,13.84,3.19,16.18,5.86,16.18,10.63,0,5.29-4.73,8.58-12.32,8.58-8.44,0-15.33-2.84-23-9.51a1,1,0,0,0-.69-.23.91.91,0,0,0-.65.34l-7.92,9.42a.94.94,0,0,0,.09,1.31A47.19,47.19,0,0,0,229.2,125c16.82,0,27.69-9.19,27.69-23.42C256.89,89.52,249.71,82.87,232.09,78.59Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<path d="M295,64.33c-7.29,0-13.27,2.87-18.21,8.75V66.46a1,1,0,0,0-.94-.95H262.85a1,1,0,0,0-.94.95v73.6a1,1,0,0,0,.94.95H275.8a1,1,0,0,0,.94-.95V116.83A23.29,23.29,0,0,0,295,125.07c13.55,0,27.27-10.43,27.27-30.37S308.5,64.33,295,64.33ZM307.16,94.7c0,10.15-6.25,17.24-15.21,17.24s-15.53-7.41-15.53-17.24S283.1,77.46,292,77.46,307.16,84.71,307.16,94.7Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<path d="M357.37,64.33c-17.45,0-31.12,13.43-31.12,30.59,0,17,13.58,30.26,30.91,30.26,17.51,0,31.22-13.39,31.22-30.48S374.76,64.33,357.37,64.33Zm0,47.72c-9.28,0-16.28-7.46-16.28-17.35s6.76-17.13,16.07-17.13S373.54,85,373.54,94.92,366.74,112.05,357.37,112.05Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<path d="M425.64,65.51H411.4V50.94a1,1,0,0,0-.95-.94H397.51a.94.94,0,0,0-.95.94V65.51h-6.23a1,1,0,0,0-.94.95V77.59a.94.94,0,0,0,.94.94h6.23v28.8c0,11.63,5.79,17.53,17.21,17.53a23.62,23.62,0,0,0,12.13-3,1,1,0,0,0,.48-.82V110.43a1,1,0,0,0-.45-.81.94.94,0,0,0-.93,0,16.35,16.35,0,0,1-7.6,1.83c-4.15,0-6-1.89-6-6.11V78.53h14.24a.94.94,0,0,0,.95-.94V66.46A1,1,0,0,0,425.64,65.51Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<path d="M475.28,65.57V63.78c0-5.27,2-7.61,6.55-7.61a21.86,21.86,0,0,1,7.29,1.34.92.92,0,0,0,.85-.13.94.94,0,0,0,.4-.77V45.7a1,1,0,0,0-.67-.91,35.73,35.73,0,0,0-10.77-1.54c-11.95,0-18.27,6.73-18.27,19.46v2.74h-6.22a1,1,0,0,0-.95,1V77.59a.94.94,0,0,0,.95.94h6.22v44.41a.94.94,0,0,0,.94,1h12.95a1,1,0,0,0,.95-1V78.53h12.08l18.52,44.4c-2.1,4.67-4.17,5.6-7,5.6a15,15,0,0,1-7.14-2,.93.93,0,0,0-1.31.44l-4.39,9.63a.93.93,0,0,0,.41,1.22,27.25,27.25,0,0,0,13.82,3.54c9.56,0,14.85-4.45,19.5-16.43l22.47-58a1,1,0,0,0-.1-.88,1,1,0,0,0-.78-.41H528.11a1,1,0,0,0-.9.63l-13.8,39.44L498.28,66.18a.94.94,0,0,0-.88-.61Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
<rect x="428.36" y="64.23" width="14.84" height="58.38" rx="0.95" ry="0.95" fill="#1ed760"/>
<path d="M440.1,39.79a9.29,9.29,0,1,0,9.28,9.28A9.28,9.28,0,0,0,440.1,39.79Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
</g>
<path d="M553.52,83.67a9.14,9.14,0,1,1,9.16-9.16A9.16,9.16,0,0,1,553.52,83.67Zm.05-17.36a8.23,8.23,0,1,0,8.15,8.2A8.15,8.15,0,0,0,553.57,66.31Zm2,9.13,2.57,3.61H556l-2.32-3.31h-2v3.31h-1.82V69.49h4.26c2.22,0,3.69,1.14,3.69,3.05A2.85,2.85,0,0,1,555.59,75.44Zm-1.54-4.31h-2.37v3h2.37c1.18,0,1.89-.58,1.89-1.51S555.23,71.13,554.05,71.13Z" transform="translate(-4.25 -1.28)" fill="#1ed760"/>
</g>
</g>
</svg>
</a>
[[[https://codepen.io/petebarr/pen/2fc0573674b0f849badd58a15371534e]]]
console.clear();
// Get the core elements
var container = document.getElementsByClassName("container");
var tube = document.getElementsByClassName("tube");
var clone = document.getElementsByClassName("clone");
var finalWrap = document.getElementsByClassName("final__wrap");
// Create the cloned nodes, append and add classes for required HTML structure - WARNING: Ugly code below 💩
var finalClone = clone[0].cloneNode(true); // clone the clean node and append to final__wrap
finalWrap[0].appendChild(finalClone).classList.add("final");
for (var i = 0; i < 2; i++) {
var newClone = clone[0].cloneNode(true); // clone the header
var lineClass = "line"+(i+2); // create class name to append
tube[0].appendChild(newClone); // append the clone
clone[i].classList.add("line"); // add cline lass
clone[i+1].classList.add(lineClass); // add incremented line class
}
clone[0].classList.add("line1"); // add line1 class to the first node
// Yuk! Now for the fun stuff…
// Show it to me!
TweenMax.set('.container', {
visibility: 'visible'
});
// Get cloned elements
var lines = document.getElementsByClassName("line");
var line1 = document.getElementsByClassName("line1");
var line2 = document.getElementsByClassName("line2");
var line3 = document.getElementsByClassName("line3");
var final = document.getElementsByClassName("final");
// split the text characters
var splitLine1 = new SplitText(line1, { type:" chars", charsClass:"char" });
var splitLine2 = new SplitText(line2, { type:" chars", charsClass:"char" });
var splitLine3 = new SplitText(line3, { type:" chars", charsClass:"char" });
var splitFinal = new SplitText(final, { type:" chars", charsClass:"char" });
// Set up vars
var animTime = 0.9; // baseline animation time for each stagger
var width = document.documentElement.clientWidth; // viewport width
var height = document.documentElement.clientHeight; // viewport height
var depth = -width/8; // rotation depth based on viewport width
var tOrigin = "50% 50% "+depth; // transform origin as a factor of viewport width to allow for different device widths
// Init 3D perspective
TweenMax.set([lines, final], { perspective:700, transformStyle:"preserve-3d"});
// Animate Timeline
var linesTL = new TimelineMax();
linesTL.staggerFromTo(splitLine1.chars, animTime, { rotationX: -90 }, { rotationX: 90, ease:Linear.easeNone, transformOrigin: tOrigin }, 0.08)
.staggerFromTo(splitLine2.chars, animTime, { rotationX: -90 }, { rotationX: 90, ease:Linear.easeNone, transformOrigin: tOrigin }, 0.08, 0.45)
.staggerFromTo(splitLine3.chars, animTime, { rotationX: -90 }, { rotationX: 90, ease:Linear.easeNone, transformOrigin: tOrigin }, 0.08, 0.9)
.staggerFromTo(splitFinal.chars, animTime*1.8, { rotationX: -90, alpha: 0 }, { rotationX: 0, alpha: 1, ease:Expo.easeOut, transformOrigin: tOrigin }, 0.06, 1.6)
.fromTo(final, animTime*5, { y:height/6 }, { y:-height/6 , ease:Power4.easeOut }, 2.0 )
// Rotate final text on mouse move
window.addEventListener("mousemove", onMouseMove);
function onMouseMove(e) {
var sxPos = (e.pageX / width*100 - 50)*2 ;
var syPos = (e.pageY / height*100 - 50)*2;
TweenMax.to(finalWrap, 3, {
rotationY: 0.04 * sxPos,
rotationX: -0.04 * syPos,
transformOrigin: "center center -800",
ease: Expo.easeOut
});
}
// linesTL.pause();
// var progressTL = new TimelineMax();
// progressTL.fromTo(linesTL, animTime*8, { progress: 0 }, { progress: 1, ease: Sine.easeOut })
/* ==========================================================================
Greensock Dev Tools
========================================================================== */
//instantiate GSDevTools with default settings
GSDevTools.create( );
/* ==========================================================================
FPS GUI stats.js
========================================================================== */
// (function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};script.src='//mrdoob.github.io/stats.js/build/stats.min.js';document.head.appendChild(script);})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.1/TweenMax.min.js"></script>
<script src="https://codepen.io/petebarr/pen/2fc0573674b0f849badd58a15371534e"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/SplitText.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/GSDevTools.min.js"></script>

Spotify Wrapped Animation using GSAP

The lovely original Spotify site https://spotifywrapped.com is built in WebGL but I wanted to have a stab at it using DOM elements and of course Greensock's GSAP using the SplitText plugin.

A Pen by Pete Barr on CodePen.

License.

html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
background: #191414;
font-family: 'Montserrat', sans-serif;
color: #F59B23;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
visibility: hidden;
}
.tube {
position: relative;
width: 100%;
height: 24vw;
// height: 16vw;
// overflow: hidden;
}
.line {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
line-height: 1;
margin: 0;
letter-spacing: -0.6vw;
font-size: 18vw;
white-space: nowrap;
text-align: center;
div {
backface-visibility: hidden;
}
}
.final__wrap {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.final {
line-height: 1;
margin: 0;
font-size: 13vw;
letter-spacing: -0.5vw;
white-space: nowrap;
div {
backface-visibility: hidden;
}
}
.logo {
position: absolute;
top: 24px;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: auto;
}
<link href="https://use.typekit.net/ekp8ytl.css" rel="stylesheet" />
<link href="https://codepen.io/petebarr/pen/2fc0573674b0f849badd58a15371534e" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment