<h1>
<span class="word">Schitt<span class="superscript">s</span> </span>
<span class="word">Creek</span>
</h1>
<input id="mute-toggle" type="checkbox" />
<label for="mute-toggle" title="Toggle sound on and">
<svg class="mute-off" viewBox="0 0 24 24">
<path
d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"
></path>
</svg>
<svg class="mute-on" viewBox="0 0 24 24">
<path
d="M12,4L9.91,6.09L12,8.18M4.27,3L3,4.27L7.73,9H3V15H7L12,20V13.27L16.25,17.53C15.58,18.04 14.83,18.46 14,18.7V20.77C15.38,20.45 16.63,19.82 17.68,18.96L19.73,21L21,19.73L12,10.73M19,12C19,12.94 18.8,13.82 18.46,14.64L19.97,16.15C20.62,14.91 21,13.5 21,12C21,7.72 18,4.14 14,3.23V5.29C16.89,6.15 19,8.83 19,12M16.5,12C16.5,10.23 15.5,8.71 14,7.97V10.18L16.45,12.63C16.5,12.43 16.5,12.21 16.5,12Z"
></path>
</svg>
</label>
@font-face {
font-family: "Playfair Display";
src: url("./PlayfairDisplay-SemiBold.ttf");
font-weight: 600 600;
}
:root {
--bar-scale-y: 0;
--sparkle-color: rgb(253 244 215 / 40%);
--sparkle-scale: 0;
--sparkle-x-position: 0;
--sparkle-y-position: 0;
--sparkle-rotation: 0;
}
body {
height: 100dvh;
margin: 0;
display: grid;
place-items: center;
background-color: black;
}
h1 {
color: white;
font-family: "Playfair Display", Vidaloka, serif;
font-size: 8rem;
line-height: 0.85;
}
.word {
display: block;
opacity: 0;
}
.word:nth-of-type(2) {
padding: 0 2rem;
color: gold;
}
.superscript {
position: relative;
vertical-align: text-top;
}
/* bars */
.superscript::before {
--bar-width: 25%;
position: absolute;
top: 37%;
left: 47%;
width: 14%;
height: 48%;
background: linear-gradient(
to right,
white var(--bar-width),
transparent var(--bar-width) calc(100% - var(--bar-width)),
white calc(100% - var(--bar-width))
);
content: "";
transform: scaleY(var(--bar-scale-y));
}
/* sparkle */
.superscript::after {
--size: 10rem;
position: absolute;
top: -5%;
left: -85%;
width: var(--size);
height: var(--size);
background: radial-gradient(
circle at center,
rgb(252 249 241 / 94%) 0% 7%,
transparent 7% 100%
),
conic-gradient(
transparent 0deg 18deg,
var(--sparkle-color) 18deg,
transparent 20deg 40deg,
var(--sparkle-color) 40deg,
transparent 43deg 87deg,
var(--sparkle-color) 87deg,
transparent 95deg 175deg,
var(--sparkle-color) 175deg,
transparent 178deg 220deg,
var(--sparkle-color) 220deg,
transparent 222deg 270deg,
var(--sparkle-color) 270deg,
transparent 275deg 300deg,
var(--sparkle-color) 300deg,
transparent 303deg 360deg
);
border-radius: 50%;
clip-path: polygon(
50% 0,
59.13% 26.64%,
85.13% -2.35%,
100% 50%,
50% 100%,
0 50%,
31.39% 34.86%
);
content: "";
filter: blur(1px);
transform: scale(var(--sparkle-scale))
translate(var(--sparkle-x-position), var(--sparkle-y-position))
rotate(var(--sparkle-rotation));
}
@media screen and (max-width: 600px) {
h1 {
font-size: 5rem;
}
/* sparkle */
.superscript::after {
--size: 6rem;
}
}
/* mute button */
/* actual checkbox is hidden */
input[type="checkbox"] {
display: none;
width: 0;
height: 0;
}
/* label acts as the interactive element */
label {
--toggle-size: clamp(1.5rem, 2.5vw, 2.5rem);
position: fixed;
top: 1rem;
right: 1rem;
width: var(--toggle-size);
height: var(--toggle-size);
background-color: white;
border-radius: 50%;
cursor: pointer;
}
/* stack 2 icons inside label */
label > svg {
position: absolute;
top: 5%;
left: 5%;
width: 90%;
height: 90%;
}
label path {
fill: black;
}
label .mute-off {
display: none;
}
/* checkbox hack to toggle visibility of SVG icons */
:checked ~ label .mute-off {
display: block;
}
:checked ~ label .mute-on {
display: none;
}
let song = new Audio("audio/intro.mp3");
song.muted = true;
const muteToggle = document.querySelector("input");
muteToggle.addEventListener("click", toggleMute);
function toggleMute() {
song.muted = !song.muted;
}
let tl = gsap.timeline({
onStart: () => {
song.currentTime = 0;
song.play();
},
});
// part 1 - propping up of words
gsap.set("h1", {
perspective: "500px",
});
gsap.set(".word", {
rotationX: 120,
transformOrigin: "50% 100%",
});
tl.to(".word:nth-of-type(1)", {
duration: 0.01,
opacity: 1,
});
tl.to(".word:nth-of-type(1)", {
duration: 1.5,
rotationX: 0,
ease: "elastic.out(1, .8).out",
});
tl.to(".word:nth-of-type(2)", {
duration: 0.01,
opacity: 1,
});
tl.to(".word:nth-of-type(2)", {
duration: 1.5,
ease: "elastic.out(1, .8).out",
rotationX: 0,
});
// part 2 - extend bars to make dollar sign of superscript S
tl.to("html", {
"--bar-scale-y": 1,
duration: 0.5,
});
// part 3 - sparkle effect
tl.to(
"html",
{
"--sparkle-scale": 1,
duration: 0.25,
},
"sparkle"
);
tl.to("html", {
"--sparkle-scale": 0,
duration: 0.15,
});
tl.to(
"html",
{
"--sparkle-x-position": "4px",
"--sparkle-y-position": "1px",
"--sparkle-rotation": "8deg",
duration: 0.2,
},
"sparkle+=0.1"
);
tl.to(
".superscript",
{
textShadow: "0 0 8px rgb(247 241 220 / 40%)",
duration: 0.2,
},
"sparkle+=0.1"
);
tl.to(
".superscript",
{
textShadow: "unset",
duration: 0.01,
},
"sparkle+=0.3"
);
// click title to restart animation
let h1 = document.getElementsByTagName("h1")[0];
h1.addEventListener("click", () => tl.restart());
This is an animation of the title card for the television series Schitts Creek. Hit the mute button (top-right corner) to hear the accompanying audio.
I wrote a tutorial on how I made this. 📖