-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
103 lines (92 loc) · 3.6 KB
/
Copy pathindex.html
File metadata and controls
103 lines (92 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>gunterlie</title>
<link rel="icon" type="image/png" href="favicon.png">
<script>
const t = 'gunterlie ';
let i = 0;
setInterval(() => { document.title = (t+t).slice(i, i+16); i = (i+1) % t.length; }, 180);
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="stage">
<div id="floats"></div>
<div class="avatar-wrap" id="avatar">
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="overflow:visible">
<defs>
<clipPath id="c">
<circle cx="100" cy="100" r="100"/>
</clipPath>
</defs>
<image
href="favicon.png"
x="0" y="0" width="200" height="200"
clip-path="url(#c)"
preserveAspectRatio="xMidYMid slice"
/>
</svg>
</div>
</div>
<p class="tagline">what did you expect?</p>
<script>
// generate excessive gunterlie
(function() {
const stage = document.querySelector('.stage');
const r = (a, b) => Math.random() * (b - a) + a;
const ri = (a, b) => Math.round(r(a, b));
const s = () => Math.random() < 0.5 ? 1 : -1;
const frag = document.createDocumentFragment();
for (let i = 0; i < 200; i++) {
const layer = Math.random();
let size, opacity, dur;
if (layer < 0.35) { size = r(0.45, 0.7); opacity = r(0.02, 0.06); dur = ri(32, 48); }
else if (layer < 0.60) { size = r(0.7, 1.1); opacity = r(0.06, 0.14); dur = ri(22, 34); }
else if (layer < 0.80) { size = r(1.1, 1.8); opacity = r(0.10, 0.22); dur = ri(16, 26); }
else { size = r(1.8, 3.2); opacity = r(0.15, 0.42); dur = ri(12, 20); }
const el = document.createElement('span');
el.className = 'float';
el.textContent = 'gunterlie';
el.style.cssText = `top:${r(0,98)}%;left:${r(-2,96)}%;font-size:${size.toFixed(2)}rem;opacity:${opacity.toFixed(2)};--dx:${s()*ri(6,28)}px;--dy:${s()*ri(6,28)}px;--dr:${s()*ri(2,14)}deg;animation-duration:${dur}s;animation-delay:-${ri(0,dur)}s`;
frag.appendChild(el);
}
stage.prepend(frag);
})();
setTimeout(() => document.querySelector('.tagline').classList.add('hidden'), 5000);
const avatar = document.getElementById('avatar');
let busy = false;
const tricks = [
() => css('spin', 600),
() => css('wobble', 700),
() => css('bounce', 600),
() => css('flip', 700),
() => css('glitch', 500),
() => css('shrink', 500),
() => css('shake', 400),
() => css('tilt', 800),
() => glow(),
];
function css(name, ms) {
avatar.style.animation = `${name} ${ms}ms ease-out, pulse 8s ease-in-out infinite`;
setTimeout(() => { avatar.style.animation = 'pulse 8s ease-in-out infinite'; busy = false; }, ms);
}
function glow() {
const colors = ['rgba(255,0,80', 'rgba(0,220,180', 'rgba(255,180,0', 'rgba(0,100,255', 'rgba(220,0,255'];
const c = colors[Math.floor(Math.random() * colors.length)];
avatar.style.setProperty('--glow', c);
avatar.style.animation = `burst 900ms ease-out, pulse 8s ease-in-out infinite`;
setTimeout(() => { avatar.style.removeProperty('--glow'); avatar.style.animation = 'pulse 8s ease-in-out infinite'; busy = false; }, 900);
}
avatar.addEventListener('click', () => {
if (busy) return;
busy = true;
tricks[Math.floor(Math.random() * tricks.length)]();
});
</script>
</body>
</html>