animate-preloader-pro 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -0
- package/animatePage.js +150 -0
- package/index.html +158 -0
- package/package.json +24 -0
- package/style.css +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
|
|
2
|
+
# animatePage.js 🎭
|
|
3
|
+
|
|
4
|
+
A high-performance, lightweight typography preloader library. **animatePage.js** transforms standard loading screens into cinematic experiences by splitting text into individual characters and applying GPU-accelerated morphing animations.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ✨ Features
|
|
9
|
+
|
|
10
|
+
* **7 Cinematic Animations:** Choose between `morph`, `wave`, `flip`, `glitch`, `blur`, `reveal`, and `pulse`.
|
|
11
|
+
* **Zero Dependencies:** 100% Vanilla JavaScript.
|
|
12
|
+
* **Staggered Letter Logic:** Automatic character-level DOM manipulation for fluid motion.
|
|
13
|
+
* **Fully Customizable:** Control colors, speeds, fonts, and sizes via a simple API.
|
|
14
|
+
* **High Performance:** Optimized with CSS `will-change` and `transform` for 60FPS smoothness.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 🚀 Installation
|
|
19
|
+
|
|
20
|
+
### 1. Manual Download
|
|
21
|
+
Download `animatePage.js` and include it in your project directory.
|
|
22
|
+
|
|
23
|
+
### 2. NPM (If published)
|
|
24
|
+
```bash
|
|
25
|
+
npm install animate-preloader-pro
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 🛠 Usage
|
|
32
|
+
|
|
33
|
+
Since this is an ES6 Module, ensure your script tag uses `type="module"`.
|
|
34
|
+
|
|
35
|
+
### 1. Basic Implementation
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
import animatePage from './animatePage.js';
|
|
39
|
+
|
|
40
|
+
// 1. Initialize settings
|
|
41
|
+
animatePage.init({
|
|
42
|
+
bg: '#0a0a0a', // Background Color
|
|
43
|
+
fg: '#00ffcc', // Text Color
|
|
44
|
+
size: '5rem', // Font Size (px, rem, vw)
|
|
45
|
+
font: 'sans-serif' // Font Family
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 2. Start the animation
|
|
49
|
+
// animatePage.on(text, animationStyle)
|
|
50
|
+
animatePage.on("LOADING", "morph");
|
|
51
|
+
|
|
52
|
+
// 3. Stop the animation
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
animatePage.off();
|
|
55
|
+
}, 3000);
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🎨 Animation Styles
|
|
62
|
+
|
|
63
|
+
| Style | Effect Description |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `morph` | **(Default)** Letters scale and skew with an organic focal blur. |
|
|
66
|
+
| `wave` | A vertical ripple effect that moves across the string. |
|
|
67
|
+
| `flip` | 3D Y-axis rotation with perspective depth. |
|
|
68
|
+
| `glitch` | High-frequency digital noise with RGB shadow shifting. |
|
|
69
|
+
| `blur` | Cinematic focal breathing where letters dissolve in/out. |
|
|
70
|
+
| `reveal` | Professional editorial mask-reveal moving upwards. |
|
|
71
|
+
| `pulse` | Soft neon glow breathing with subtle scaling. |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## ⚙️ API Reference
|
|
76
|
+
|
|
77
|
+
### `animatePage.init(options)`
|
|
78
|
+
|
|
79
|
+
Configures the global styles and behaviors.
|
|
80
|
+
|
|
81
|
+
| Option | Type | Default | Description |
|
|
82
|
+
| --- | --- | --- | --- |
|
|
83
|
+
| `bg` | `string` | `"#000"` | Background color. |
|
|
84
|
+
| `fg` | `string` | `"#fff"` | Letter color. |
|
|
85
|
+
| `size` | `string` | `"5rem"` | Font size. |
|
|
86
|
+
| `speed` | `number` | `2` | Speed of one animation cycle (seconds). |
|
|
87
|
+
| `fadeTime` | `number` | `600` | Fade-out duration on `off()` (ms). |
|
|
88
|
+
| `font` | `string` | `"sans-serif"` | Font family. |
|
|
89
|
+
|
|
90
|
+
### `animatePage.on(text, animation)`
|
|
91
|
+
|
|
92
|
+
Triggers the preloader overlay.
|
|
93
|
+
|
|
94
|
+
* **text**: The string you want to animate.
|
|
95
|
+
* **animation**: The style key (e.g., `"glitch"`).
|
|
96
|
+
|
|
97
|
+
### `animatePage.off()`
|
|
98
|
+
|
|
99
|
+
Fades out and removes the preloader from the DOM.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 🌟 Pro Tip: Dynamic Loading
|
|
104
|
+
|
|
105
|
+
For real-world apps, trigger `.off()` inside a window load event:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
window.addEventListener('load', () => {
|
|
109
|
+
animatePage.off();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 📄 License
|
|
115
|
+
|
|
116
|
+
MIT © Itzbandhan
|
package/animatePage.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* animatePage.js v1.0.0
|
|
3
|
+
* A high-performance typography preloader library.
|
|
4
|
+
* Features: Morph, Wave, Flip, Glitch, Blur, Reveal, Pulse.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const animatePage = (() => {
|
|
8
|
+
let el = null;
|
|
9
|
+
let config = {
|
|
10
|
+
text: "LOADING",
|
|
11
|
+
bg: "#000000",
|
|
12
|
+
fg: "#ffffff",
|
|
13
|
+
size: "5rem",
|
|
14
|
+
weight: "900",
|
|
15
|
+
speed: 2,
|
|
16
|
+
fadeTime: 600,
|
|
17
|
+
animation: "morph",
|
|
18
|
+
font: "sans-serif"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const injectStyles = () => {
|
|
22
|
+
if (document.getElementById("ap-core-styles")) return;
|
|
23
|
+
const s = document.createElement("style");
|
|
24
|
+
s.id = "ap-core-styles";
|
|
25
|
+
s.innerHTML = `
|
|
26
|
+
:root {
|
|
27
|
+
--ap-bg: ${config.bg};
|
|
28
|
+
--ap-fg: ${config.fg};
|
|
29
|
+
--ap-size: ${config.size};
|
|
30
|
+
--ap-speed: ${config.speed}s;
|
|
31
|
+
--ap-fade: ${config.fadeTime}ms;
|
|
32
|
+
--ap-font: ${config.font};
|
|
33
|
+
}
|
|
34
|
+
#ap-overlay {
|
|
35
|
+
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
|
|
36
|
+
background: var(--ap-bg); color: var(--ap-fg);
|
|
37
|
+
display: flex; align-items: center; justify-content: center;
|
|
38
|
+
z-index: 99999; transition: opacity var(--ap-fade) cubic-bezier(0.4, 0, 0.2, 1);
|
|
39
|
+
font-family: var(--ap-font); overflow: hidden;
|
|
40
|
+
}
|
|
41
|
+
.ap-letter {
|
|
42
|
+
display: inline-block;
|
|
43
|
+
font-size: var(--ap-size);
|
|
44
|
+
font-weight: 900;
|
|
45
|
+
text-transform: uppercase;
|
|
46
|
+
will-change: transform, opacity, filter;
|
|
47
|
+
backface-visibility: hidden;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* 1. MORPH - Organic stretching and blurring */
|
|
51
|
+
.anim-morph { animation: ap-morph var(--ap-speed) infinite ease-in-out; }
|
|
52
|
+
@keyframes ap-morph {
|
|
53
|
+
0%, 100% { transform: scale(1) rotate(0deg); filter: blur(0); }
|
|
54
|
+
50% { transform: scale(1.4, 0.7) rotate(5deg); filter: blur(4px); opacity: 0.5; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* 2. WAVE - Staggered vertical ripple */
|
|
58
|
+
.anim-wave { animation: ap-wave var(--ap-speed) infinite ease-in-out; }
|
|
59
|
+
@keyframes ap-wave {
|
|
60
|
+
0%, 100% { transform: translateY(0); }
|
|
61
|
+
50% { transform: translateY(-40px); opacity: 0.6; }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* 3. FLIP - Smooth 3D Y-axis rotation */
|
|
65
|
+
.anim-flip { animation: ap-flip var(--ap-speed) infinite ease-in-out; perspective: 1000px; }
|
|
66
|
+
@keyframes ap-flip {
|
|
67
|
+
0% { transform: rotateY(0deg); }
|
|
68
|
+
50% { transform: rotateY(180deg); opacity: 0.4; }
|
|
69
|
+
100% { transform: rotateY(360deg); }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* 4. GLITCH - High-frequency digital noise */
|
|
73
|
+
.anim-glitch { animation: ap-glitch 0.2s infinite; }
|
|
74
|
+
@keyframes ap-glitch {
|
|
75
|
+
0% { transform: translate(0); text-shadow: 2px 0 var(--ap-fg); }
|
|
76
|
+
25% { transform: translate(-3px, 1px); text-shadow: -2px 0 #ff00c1; }
|
|
77
|
+
50% { transform: translate(3px, -1px); text-shadow: 2px 0 #00fff9; }
|
|
78
|
+
100% { transform: translate(0); }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* 5. BLUR - Soft focal breathing */
|
|
82
|
+
.anim-blur { animation: ap-blur var(--ap-speed) infinite ease-in-out; }
|
|
83
|
+
@keyframes ap-blur {
|
|
84
|
+
0%, 100% { filter: blur(25px); opacity: 0; transform: scale(0.7); }
|
|
85
|
+
50% { filter: blur(0); opacity: 1; transform: scale(1.1); }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* 6. REVEAL - Modern upward mask slide */
|
|
89
|
+
.anim-reveal { animation: ap-reveal var(--ap-speed) infinite ease-in-out; }
|
|
90
|
+
@keyframes ap-reveal {
|
|
91
|
+
0%, 100% { clip-path: inset(0 0 100% 0); transform: translateY(30px); }
|
|
92
|
+
50% { clip-path: inset(0 0 0% 0); transform: translateY(0); }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* 7. PULSE - Neon glow and scale breathing */
|
|
96
|
+
.anim-pulse { animation: ap-pulse var(--ap-speed) infinite ease-in-out; }
|
|
97
|
+
@keyframes ap-pulse {
|
|
98
|
+
0%, 100% { transform: scale(1); filter: drop-shadow(0 0 0px var(--ap-fg)); opacity: 1; }
|
|
99
|
+
50% { transform: scale(0.85); filter: drop-shadow(0 0 25px var(--ap-fg)); opacity: 0.3; }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ap-hide { opacity: 0; pointer-events: none; }
|
|
103
|
+
`;
|
|
104
|
+
document.head.appendChild(s);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const syncVars = () => {
|
|
108
|
+
const root = document.documentElement;
|
|
109
|
+
root.style.setProperty('--ap-bg', config.bg);
|
|
110
|
+
root.style.setProperty('--ap-fg', config.fg);
|
|
111
|
+
root.style.setProperty('--ap-size', config.size);
|
|
112
|
+
root.style.setProperty('--ap-speed', config.speed + 's');
|
|
113
|
+
root.style.setProperty('--ap-fade', config.fadeTime + 'ms');
|
|
114
|
+
root.style.setProperty('--ap-font', config.font);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
init(options = {}) {
|
|
119
|
+
config = { ...config, ...options };
|
|
120
|
+
injectStyles();
|
|
121
|
+
syncVars();
|
|
122
|
+
return this;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
on(text = config.text, animation = config.animation) {
|
|
126
|
+
if (el) return;
|
|
127
|
+
injectStyles();
|
|
128
|
+
syncVars();
|
|
129
|
+
|
|
130
|
+
el = document.createElement("div");
|
|
131
|
+
el.id = "ap-overlay";
|
|
132
|
+
|
|
133
|
+
const charArray = text.split("");
|
|
134
|
+
el.innerHTML = charArray.map((char, i) => {
|
|
135
|
+
const delay = (i * 0.1).toFixed(2);
|
|
136
|
+
return `<span class="ap-letter anim-${animation}" style="animation-delay: ${delay}s">${char === " " ? " " : char}</span>`;
|
|
137
|
+
}).join("");
|
|
138
|
+
|
|
139
|
+
document.body.appendChild(el);
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
off() {
|
|
143
|
+
if (!el) return;
|
|
144
|
+
el.classList.add("ap-hide");
|
|
145
|
+
setTimeout(() => { if (el) { el.remove(); el = null; } }, config.fadeTime);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
})();
|
|
149
|
+
|
|
150
|
+
export default animatePage;
|
package/index.html
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>animatePage Pro - Test Suite</title>
|
|
7
|
+
<style>
|
|
8
|
+
/* Modern Dark UI Dashboard */
|
|
9
|
+
body {
|
|
10
|
+
background: #0a0a0a;
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: 'Inter', -apple-system, sans-serif;
|
|
13
|
+
height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
margin: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dashboard {
|
|
22
|
+
background: #151515;
|
|
23
|
+
padding: 35px;
|
|
24
|
+
border-radius: 20px;
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-columns: 1fr 1fr;
|
|
27
|
+
gap: 20px;
|
|
28
|
+
box-shadow: 0 20px 50px rgba(0,0,0,0.6);
|
|
29
|
+
border: 1px solid #222;
|
|
30
|
+
width: 450px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.full-span { grid-column: span 2; }
|
|
34
|
+
|
|
35
|
+
h1 {
|
|
36
|
+
margin-top: 0;
|
|
37
|
+
font-size: 1rem;
|
|
38
|
+
color: #555;
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
letter-spacing: 3px;
|
|
41
|
+
text-align: center;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.control-group { display: flex; flex-direction: column; gap: 8px; }
|
|
45
|
+
|
|
46
|
+
label {
|
|
47
|
+
font-size: 0.7rem;
|
|
48
|
+
color: #888;
|
|
49
|
+
font-weight: bold;
|
|
50
|
+
text-transform: uppercase;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
button {
|
|
54
|
+
padding: 15px;
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
border: none;
|
|
57
|
+
border-radius: 8px;
|
|
58
|
+
font-weight: 800;
|
|
59
|
+
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
60
|
+
text-transform: uppercase;
|
|
61
|
+
letter-spacing: 1px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.trigger {
|
|
65
|
+
background: #fff;
|
|
66
|
+
color: #000;
|
|
67
|
+
margin-top: 10px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.trigger:hover {
|
|
71
|
+
background: #00ffcc;
|
|
72
|
+
transform: translateY(-3px);
|
|
73
|
+
box-shadow: 0 10px 20px rgba(0, 255, 204, 0.2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
select, input {
|
|
77
|
+
padding: 12px;
|
|
78
|
+
background: #222;
|
|
79
|
+
border: 1px solid #333;
|
|
80
|
+
color: white;
|
|
81
|
+
border-radius: 8px;
|
|
82
|
+
outline: none;
|
|
83
|
+
font-size: 0.9rem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
input[type="color"] {
|
|
87
|
+
height: 45px;
|
|
88
|
+
padding: 5px;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
92
|
+
</head>
|
|
93
|
+
<body>
|
|
94
|
+
|
|
95
|
+
<div class="dashboard">
|
|
96
|
+
<h1 class="full-span">animatePage.js Config</h1>
|
|
97
|
+
|
|
98
|
+
<div class="control-group full-span">
|
|
99
|
+
<label>Animation Style</label>
|
|
100
|
+
<select id="animSelect">
|
|
101
|
+
<option value="morph">Morphing (Cinematic)</option>
|
|
102
|
+
<option value="wave">Wave (Ripple)</option>
|
|
103
|
+
<option value="flip">3D Flip (Vertical)</option>
|
|
104
|
+
<option value="glitch">Glitch (Digital)</option>
|
|
105
|
+
<option value="blur">Blur (Focal)</option>
|
|
106
|
+
<option value="reveal">Reveal (Editorial)</option>
|
|
107
|
+
<option value="pulse">Pulse (Neon)</option>
|
|
108
|
+
</select>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div class="control-group full-span">
|
|
112
|
+
<label>Text Content</label>
|
|
113
|
+
<input type="text" id="loaderText" value="ANIMATE">
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div class="control-group">
|
|
117
|
+
<label>Text Color</label>
|
|
118
|
+
<input type="color" id="fgColor" value="#00ffcc">
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="control-group">
|
|
122
|
+
<label>Background</label>
|
|
123
|
+
<input type="color" id="bgColor" value="#0a0a0a">
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<button class="full-span trigger" onclick="testLoader()">Run Preloader ▶</button>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<script type="module">
|
|
130
|
+
import animatePage from './animatePage.js';
|
|
131
|
+
|
|
132
|
+
window.testLoader = function() {
|
|
133
|
+
// 1. Capture Current UI Values
|
|
134
|
+
const text = document.getElementById('loaderText').value;
|
|
135
|
+
const anim = document.getElementById('animSelect').value;
|
|
136
|
+
const fg = document.getElementById('fgColor').value;
|
|
137
|
+
const bg = document.getElementById('bgColor').value;
|
|
138
|
+
|
|
139
|
+
// 2. Initialize the engine with new styles
|
|
140
|
+
animatePage.init({
|
|
141
|
+
bg: bg,
|
|
142
|
+
fg: fg,
|
|
143
|
+
size: "6vw",
|
|
144
|
+
speed: (anim === 'glitch') ? 0.25 : 2,
|
|
145
|
+
fadeTime: 600
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// 3. Trigger the animation
|
|
149
|
+
animatePage.on(text, anim);
|
|
150
|
+
|
|
151
|
+
// 4. Auto-hide after 4 seconds
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
animatePage.off();
|
|
154
|
+
}, 4000);
|
|
155
|
+
}
|
|
156
|
+
</script>
|
|
157
|
+
</body>
|
|
158
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "animate-preloader-pro",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight, modular, typography-based preloader library with cinematic morphing animations.",
|
|
5
|
+
"main": "animatePage.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"preloader",
|
|
12
|
+
"animation",
|
|
13
|
+
"typography",
|
|
14
|
+
"morph",
|
|
15
|
+
"javascript",
|
|
16
|
+
"ui",
|
|
17
|
+
"frontend"
|
|
18
|
+
],
|
|
19
|
+
"author": "Itzbandhan",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/style.css
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--ib-bg: #000;
|
|
3
|
+
--ib-fg: #fff;
|
|
4
|
+
--ib-t: 0.6s; /* Fade out speed */
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
#ib-wrap {
|
|
8
|
+
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
|
|
9
|
+
background: var(--ib-bg); color: var(--ib-fg);
|
|
10
|
+
display: flex; align-items: center; justify-content: center;
|
|
11
|
+
z-index: 9999; transition: opacity var(--ib-t) ease-in;
|
|
12
|
+
font-family: 'Inter', sans-serif; overflow: hidden;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Individual Letter Container */
|
|
16
|
+
.ib-letter {
|
|
17
|
+
display: inline-block;
|
|
18
|
+
font-size: 4rem;
|
|
19
|
+
font-weight: 900;
|
|
20
|
+
letter-spacing: 5px;
|
|
21
|
+
text-transform: uppercase;
|
|
22
|
+
animation: ib-morph 2s infinite ease-in-out;
|
|
23
|
+
filter: blur(0px);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@keyframes ib-morph {
|
|
27
|
+
0%, 100% {
|
|
28
|
+
transform: scale(1) skewX(0deg);
|
|
29
|
+
filter: blur(0px);
|
|
30
|
+
opacity: 1;
|
|
31
|
+
}
|
|
32
|
+
50% {
|
|
33
|
+
transform: scale(1.2) skewX(-10deg);
|
|
34
|
+
filter: blur(2px);
|
|
35
|
+
opacity: 0.7;
|
|
36
|
+
letter-spacing: 15px;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ib-hide { opacity: 0; pointer-events: none; }
|