├── main.css
├── index.html
└── app.js
/main.css:
--------------------------------------------------------------------------------
1 | /* Explanation in JS tab */
2 |
3 | /* Cool font from Google Fonts! */
4 | @import url('https://fonts.googleapis.com/css?family=Raleway:700&display=swap');
5 |
6 | body {
7 | margin: 0px;
8 | }
9 |
10 | #container {
11 | /* Center the text in the viewport. */
12 | position: absolute;
13 | margin: auto;
14 | width: 100vw;
15 | height: 80pt;
16 | top: 0;
17 | bottom: 0;
18 |
19 | /* This filter is a lot of the magic, try commenting it out to see how the morphing works! */
20 | filter: url(#threshold) blur(0.6px);
21 | }
22 |
23 | /* Your average text styling */
24 | #text1, #text2 {
25 | position: absolute;
26 | width: 100%;
27 | display: inline-block;
28 |
29 | font-family: 'Raleway', sans-serif;
30 | font-size: 80pt;
31 |
32 | text-align: center;
33 |
34 | user-select: none;
35 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Someday... || Me
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | This pen cleverly utilizes SVG filters to create a "Morphing Text" effect. Essentially, it layers 2 text elements on top of each other, and blurs them depending on which text element should be more visible. Once the blurring is applied, both texts are fed through a threshold filter together, which produces the "gooey" effect. Check the CSS - Comment the #container rule's filter out to see how the blurring works!
3 | */
4 |
5 | const elts = {
6 | text1: document.getElementById("text1"),
7 | text2: document.getElementById("text2")
8 | };
9 |
10 | // The strings to morph between. You can change these to anything you want!
11 | const texts = [
12 | "I",
13 | "Love",
14 | "You",
15 | "My",
16 | "Dream",
17 | "😇",
18 | "❤️"
19 | ];
20 |
21 | // Controls the speed of morphing.
22 | const morphTime = 1;
23 | const cooldownTime = 0.25;
24 |
25 | let textIndex = texts.length - 1;
26 | let time = new Date();
27 | let morph = 0;
28 | let cooldown = cooldownTime;
29 |
30 | elts.text1.textContent = texts[textIndex % texts.length];
31 | elts.text2.textContent = texts[(textIndex + 1) % texts.length];
32 |
33 | function doMorph() {
34 | morph -= cooldown;
35 | cooldown = 0;
36 |
37 | let fraction = morph / morphTime;
38 |
39 | if (fraction > 1) {
40 | cooldown = cooldownTime;
41 | fraction = 1;
42 | }
43 |
44 | setMorph(fraction);
45 | }
46 |
47 | // A lot of the magic happens here, this is what applies the blur filter to the text.
48 | function setMorph(fraction) {
49 | // fraction = Math.cos(fraction * Math.PI) / -2 + .5;
50 |
51 | elts.text2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
52 | elts.text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
53 |
54 | fraction = 1 - fraction;
55 | elts.text1.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
56 | elts.text1.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
57 |
58 | elts.text1.textContent = texts[textIndex % texts.length];
59 | elts.text2.textContent = texts[(textIndex + 1) % texts.length];
60 | }
61 |
62 | function doCooldown() {
63 | morph = 0;
64 |
65 | elts.text2.style.filter = "";
66 | elts.text2.style.opacity = "100%";
67 |
68 | elts.text1.style.filter = "";
69 | elts.text1.style.opacity = "0%";
70 | }
71 |
72 | // Animation loop, which is called every frame.
73 | function animate() {
74 | requestAnimationFrame(animate);
75 |
76 | let newTime = new Date();
77 | let shouldIncrementIndex = cooldown > 0;
78 | let dt = (newTime - time) / 1000;
79 | time = newTime;
80 |
81 | cooldown -= dt;
82 |
83 | if (cooldown <= 0) {
84 | if (shouldIncrementIndex) {
85 | textIndex++;
86 | }
87 |
88 | doMorph();
89 | } else {
90 | doCooldown();
91 | }
92 | }
93 |
94 | // Start the animation.
95 | animate();
--------------------------------------------------------------------------------