Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
355 lines (318 loc) · 33.1 KB
/
Copy pathindex.html
File metadata and controls
355 lines (318 loc) · 33.1 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>gunterlie</title>
<meta name="description" content="what did you expect?">
<meta name="theme-color" content="#0b0604">
<meta property="og:title" content="gunterlie">
<meta property="og:description" content="what did you expect?">
<meta property="og:type" content="website">
<meta property="og:url" content="https://gunterlie.de">
<meta property="og:image" content="https://gunterlie.de/og.png">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" type="image/svg+xml" href="gface.svg?v=2">
<link rel="icon" type="image/png" href="favicon.png">
<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?v=6">
</head>
<body>
<div class="stage">
<div id="floats"></div>
<div class="log" id="log" aria-hidden="true"></div>
<p class="tagline" id="tagline">what did you expect?</p>
<div class="face-wrap" id="avatar" role="button" tabindex="0" aria-label="gunterlie. click for chaos">
<div class="face" id="face">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1254 1254"
preserveAspectRatio="xMidYMid meet" aria-hidden="true">
<desc>
Vector traced from the approved concept image.
Animation-ready parts: locks, head shape, left brow, right brow, moustache and beard.
</desc>
<style>
.anim-part {
transform-box: fill-box;
transform-origin: center;
}
/* Subtle hair movement */
#locks {
transform-box: fill-box;
transform-origin: 50% 70%;
animation: hair-sway 2.6s ease-in-out infinite alternate;
}
@keyframes hair-sway {
0% { transform: rotate(-0.8deg) translateY(0px) scaleX(1); }
50% { transform: rotate(0.45deg) translateY(-1.5px) scaleX(1.006); }
100% { transform: rotate(0.8deg) translateY(0px) scaleX(0.997); }
}
/* Existing expressive motion */
#moustache {
transform-box: fill-box;
transform-origin: center;
animation: moustache-twitch 1.1s ease-in-out infinite alternate;
}
#brow-left {
transform-box: fill-box;
transform-origin: center;
animation: brow-left-move 1.25s ease-in-out infinite alternate;
}
#brow-right {
transform-box: fill-box;
transform-origin: center;
animation: brow-right-move 1.25s ease-in-out infinite alternate;
}
@keyframes moustache-twitch {
0% { transform: rotate(-1.5deg) scaleX(1); }
45% { transform: rotate(1deg) scaleX(1.025); }
100% { transform: rotate(-0.5deg) scaleX(.985); }
}
@keyframes brow-left-move {
from { transform: translateY(0px) rotate(-2deg); }
to { transform: translateY(-8px) rotate(3deg); }
}
@keyframes brow-right-move {
from { transform: translateY(0px) rotate(2deg); }
to { transform: translateY(-8px) rotate(-3deg); }
}
@media (prefers-reduced-motion: reduce) {
#locks, #moustache, #brow-left, #brow-right { animation: none; }
}
</style>
<!-- Separate background so it can be deleted for transparency -->
<g id="gunterlie">
<!-- Enlarged duplicate face shape behind everything -->
<path id="head-shape-backup"
d="M 437 328 L 416 340 L 398 356 L 378 382 L 365 404 L 347 442 L 340 462 L 338 465 L 333 482 L 331 485 L 331 488 L 326 501 L 326 504 L 320 522 L 311 562 L 326 546 L 328 547 L 322 587 L 321 588 L 319 611 L 318 612 L 316 634 L 315 635 L 315 643 L 314 644 L 312 670 L 311 671 L 311 680 L 310 681 L 310 690 L 309 691 L 308 716 L 307 717 L 306 789 L 307 790 L 307 803 L 308 804 L 309 819 L 310 820 L 310 825 L 311 826 L 314 844 L 322 869 L 337 900 L 349 918 L 363 935 L 393 963 L 393 988 L 394 989 L 394 1074 L 392 1076 L 394 1077 L 394 1160 L 397 1163 L 424 1175 L 450 1183 L 454 1183 L 480 1190 L 495 1192 L 501 1194 L 506 1194 L 507 1195 L 535 1198 L 536 1199 L 566 1201 L 567 1202 L 580 1202 L 581 1203 L 601 1203 L 602 1204 L 672 1203 L 673 1202 L 698 1201 L 699 1200 L 708 1200 L 709 1199 L 717 1199 L 718 1198 L 746 1195 L 747 1194 L 758 1193 L 764 1191 L 769 1191 L 778 1188 L 782 1188 L 787 1186 L 803 1183 L 832 1174 L 855 1164 L 860 1160 L 860 1067 L 861 1066 L 862 1067 L 860 1065 L 860 963 L 882 944 L 896 929 L 909 912 L 919 896 L 930 873 L 938 850 L 943 829 L 945 810 L 946 809 L 946 800 L 947 799 L 948 745 L 947 744 L 947 722 L 946 721 L 945 695 L 944 694 L 942 663 L 941 662 L 941 654 L 940 653 L 940 646 L 939 645 L 939 637 L 938 636 L 935 605 L 934 604 L 934 598 L 933 597 L 933 591 L 931 584 L 931 578 L 930 577 L 930 571 L 929 570 L 926 547 L 927 546 L 941 560 L 942 556 L 938 543 L 938 539 L 934 523 L 926 498 L 926 495 L 912 455 L 901 431 L 901 429 L 887 401 L 877 384 L 860 361 L 844 345 L 832 336 L 817 328 L 801 323 L 791 322 L 790 321 L 778 321 L 777 320 L 751 321 L 750 322 L 736 323 L 735 324 L 731 324 L 730 325 L 709 329 L 685 337 L 680 340 L 671 343 L 663 348 L 661 348 L 647 356 L 632 366 L 628 370 L 626 370 L 603 354 L 580 342 L 578 342 L 563 335 L 533 326 L 512 323 L 511 322 L 504 322 L 503 321 L 476 320 L 475 321 L 463 321 L 462 322 L 452 323 Z"
fill="#FDE2C4"
transform="translate(627 620) scale(1.10 1.08) translate(-627 -620)"/>
<!-- Wild hair / locks -->
<g id="locks" class="anim-part">
<path id="hair-silhouette" d="M 292 51 L 279 65 L 268 84 L 262 105 L 261 123 L 262 124 L 264 140 L 267 149 L 274 163 L 282 174 L 294 186 L 308 196 L 297 205 L 282 215 L 267 223 L 250 228 L 235 228 L 227 226 L 218 221 L 211 214 L 207 208 L 204 200 L 203 189 L 206 177 L 212 167 L 220 159 L 219 160 L 218 159 L 204 160 L 187 165 L 177 170 L 167 177 L 154 190 L 147 200 L 141 212 L 138 221 L 137 229 L 136 230 L 136 237 L 135 238 L 136 255 L 139 267 L 147 284 L 156 296 L 167 306 L 166 307 L 145 307 L 144 308 L 136 308 L 135 309 L 130 309 L 122 311 L 100 320 L 85 330 L 68 348 L 64 354 L 57 369 L 54 379 L 53 396 L 52 397 L 53 398 L 53 407 L 54 408 L 55 417 L 59 428 L 66 440 L 80 454 L 80 440 L 84 427 L 91 415 L 104 402 L 120 392 L 140 385 L 156 383 L 157 382 L 171 382 L 172 383 L 162 392 L 149 408 L 139 424 L 129 444 L 125 455 L 115 474 L 106 487 L 93 500 L 76 509 L 72 510 L 56 510 L 46 506 L 36 498 L 32 511 L 31 528 L 32 529 L 33 541 L 41 561 L 52 576 L 61 584 L 78 594 L 96 600 L 108 601 L 115 603 L 92 618 L 73 636 L 62 651 L 53 669 L 48 688 L 47 704 L 48 705 L 48 714 L 51 727 L 58 743 L 69 758 L 78 765 L 79 756 L 83 746 L 89 737 L 98 728 L 106 722 L 119 715 L 143 707 L 147 708 L 142 716 L 132 738 L 118 785 L 112 798 L 106 807 L 100 814 L 90 822 L 74 828 L 61 828 L 57 827 L 42 819 L 43 838 L 50 859 L 59 873 L 72 886 L 90 897 L 108 903 L 121 904 L 122 905 L 132 905 L 133 904 L 148 903 L 169 897 L 174 894 L 176 895 L 168 904 L 155 923 L 147 940 L 141 963 L 140 979 L 141 980 L 141 989 L 142 990 L 143 999 L 151 1019 L 160 1032 L 172 1044 L 188 1054 L 208 1060 L 221 1060 L 215 1051 L 211 1036 L 211 1025 L 215 1011 L 223 998 L 234 987 L 251 977 L 261 974 L 263 982 L 263 989 L 266 997 L 266 1000 L 276 1019 L 286 1030 L 297 1038 L 319 1047 L 319 1051 L 316 1061 L 308 1074 L 302 1080 L 292 1086 L 282 1089 L 275 1089 L 280 1094 L 295 1103 L 305 1106 L 309 1106 L 310 1107 L 334 1107 L 347 1104 L 364 1097 L 382 1085 L 393 1074 L 392 963 L 378 951 L 362 935 L 351 922 L 339 905 L 332 893 L 321 869 L 314 848 L 310 827 L 309 826 L 307 804 L 306 803 L 306 791 L 305 790 L 306 715 L 307 714 L 309 680 L 310 679 L 312 651 L 313 650 L 313 643 L 314 642 L 314 635 L 315 634 L 315 627 L 316 626 L 316 618 L 317 617 L 320 588 L 321 587 L 327 547 L 311 563 L 310 560 L 320 518 L 338 462 L 349 437 L 349 435 L 353 428 L 353 426 L 364 404 L 379 379 L 397 356 L 406 347 L 420 336 L 437 327 L 448 323 L 461 321 L 462 320 L 475 320 L 476 319 L 511 321 L 512 322 L 518 322 L 519 323 L 523 323 L 524 324 L 545 328 L 571 337 L 598 350 L 623 366 L 626 369 L 661 347 L 685 336 L 705 329 L 712 328 L 720 325 L 735 323 L 736 322 L 742 322 L 743 321 L 749 321 L 750 320 L 764 320 L 765 319 L 791 320 L 792 321 L 797 321 L 817 327 L 827 332 L 843 343 L 862 362 L 874 378 L 884 394 L 907 440 L 915 460 L 916 465 L 918 468 L 928 498 L 928 501 L 932 512 L 933 519 L 935 523 L 942 551 L 942 555 L 944 561 L 943 563 L 927 547 L 928 558 L 929 559 L 930 570 L 932 577 L 932 583 L 934 590 L 935 603 L 936 604 L 936 611 L 937 612 L 937 619 L 938 620 L 938 627 L 939 628 L 939 635 L 940 636 L 940 644 L 941 645 L 941 653 L 942 654 L 942 662 L 943 663 L 943 671 L 944 672 L 946 706 L 947 707 L 947 720 L 948 721 L 948 739 L 949 740 L 949 785 L 948 786 L 948 800 L 947 801 L 947 810 L 946 811 L 944 830 L 942 835 L 940 847 L 937 854 L 937 857 L 929 878 L 920 896 L 902 923 L 881 946 L 861 963 L 861 1065 L 868 1074 L 883 1088 L 895 1096 L 907 1102 L 922 1107 L 931 1108 L 932 1109 L 955 1109 L 970 1105 L 983 1098 L 983 1097 L 976 1096 L 968 1092 L 958 1081 L 953 1069 L 953 1052 L 955 1044 L 959 1035 L 968 1022 L 992 1037 L 1010 1043 L 1020 1044 L 1021 1045 L 1047 1045 L 1048 1044 L 1057 1043 L 1074 1037 L 1090 1027 L 1102 1015 L 1107 1008 L 1113 996 L 1117 982 L 1104 988 L 1088 990 L 1087 989 L 1078 988 L 1062 980 L 1052 970 L 1047 962 L 1042 950 L 1041 942 L 1040 941 L 1040 932 L 1039 931 L 1041 909 L 1046 894 L 1060 898 L 1074 905 L 1092 923 L 1098 936 L 1099 949 L 1112 940 L 1122 930 L 1136 910 L 1142 897 L 1147 880 L 1148 869 L 1149 868 L 1149 851 L 1148 850 L 1148 843 L 1147 842 L 1146 832 L 1138 806 L 1128 785 L 1117 768 L 1118 766 L 1128 766 L 1129 767 L 1138 768 L 1147 771 L 1164 781 L 1174 791 L 1178 797 L 1183 809 L 1184 818 L 1192 808 L 1198 796 L 1203 779 L 1204 754 L 1203 753 L 1203 746 L 1202 745 L 1201 736 L 1192 711 L 1185 698 L 1167 673 L 1151 655 L 1127 632 L 1128 631 L 1141 631 L 1142 630 L 1163 630 L 1180 634 L 1193 641 L 1204 653 L 1208 663 L 1209 663 L 1214 649 L 1215 640 L 1216 639 L 1216 622 L 1215 621 L 1214 611 L 1206 589 L 1198 576 L 1190 566 L 1179 555 L 1163 542 L 1135 524 L 1129 519 L 1130 518 L 1142 519 L 1143 520 L 1164 519 L 1183 513 L 1197 504 L 1208 492 L 1215 479 L 1218 468 L 1218 451 L 1212 456 L 1199 461 L 1186 461 L 1178 459 L 1168 454 L 1160 448 L 1150 436 L 1143 423 L 1130 380 L 1121 362 L 1111 348 L 1100 337 L 1082 324 L 1095 320 L 1112 319 L 1113 320 L 1121 320 L 1129 322 L 1142 328 L 1148 332 L 1158 342 L 1163 349 L 1167 359 L 1169 373 L 1176 364 L 1183 350 L 1186 339 L 1186 333 L 1187 332 L 1187 320 L 1186 319 L 1186 312 L 1181 296 L 1174 283 L 1168 275 L 1158 265 L 1144 255 L 1129 248 L 1111 243 L 1106 243 L 1105 242 L 1074 242 L 1073 243 L 1068 243 L 1067 244 L 1062 244 L 1040 251 L 1038 250 L 1049 238 L 1062 217 L 1069 198 L 1069 194 L 1071 189 L 1071 182 L 1072 181 L 1072 167 L 1071 166 L 1071 159 L 1068 147 L 1060 129 L 1051 116 L 1035 101 L 1017 91 L 999 86 L 979 86 L 993 99 L 1002 113 L 1007 129 L 1007 150 L 1002 168 L 996 180 L 990 189 L 978 202 L 972 188 L 962 172 L 947 156 L 937 148 L 924 140 L 903 131 L 886 127 L 881 127 L 880 126 L 851 126 L 850 127 L 844 127 L 819 134 L 803 142 L 792 149 L 791 148 L 792 123 L 791 122 L 790 111 L 784 93 L 777 80 L 771 72 L 757 58 L 749 52 L 730 42 L 714 37 L 703 36 L 702 35 L 681 35 L 675 37 L 683 43 L 694 55 L 702 69 L 706 81 L 706 86 L 707 87 L 707 107 L 706 108 L 706 113 L 701 129 L 699 128 L 694 118 L 680 99 L 669 88 L 655 77 L 641 68 L 627 61 L 605 53 L 588 49 L 576 48 L 575 47 L 563 47 L 562 46 L 543 46 L 542 47 L 531 47 L 530 48 L 518 49 L 517 50 L 496 54 L 463 66 L 432 82 L 405 98 L 391 103 L 379 104 L 378 105 L 363 103 L 352 98 L 342 89 L 336 79 L 333 68 L 333 59 L 335 51 L 340 41 L 350 31 L 334 31 L 317 36 L 303 43 Z" fill="#F96001"/>
</g>
<!-- Blank head shape -->
<path id="head-shape" class="anim-part" d="M 437 328 L 416 340 L 398 356 L 378 382 L 365 404 L 347 442 L 340 462 L 338 465 L 333 482 L 331 485 L 331 488 L 326 501 L 326 504 L 320 522 L 311 562 L 326 546 L 328 547 L 322 587 L 321 588 L 319 611 L 318 612 L 316 634 L 315 635 L 315 643 L 314 644 L 312 670 L 311 671 L 311 680 L 310 681 L 310 690 L 309 691 L 308 716 L 307 717 L 306 789 L 307 790 L 307 803 L 308 804 L 309 819 L 310 820 L 310 825 L 311 826 L 314 844 L 322 869 L 337 900 L 349 918 L 363 935 L 393 963 L 393 988 L 394 989 L 394 1074 L 392 1076 L 394 1077 L 394 1160 L 397 1163 L 424 1175 L 450 1183 L 454 1183 L 480 1190 L 495 1192 L 501 1194 L 506 1194 L 507 1195 L 535 1198 L 536 1199 L 566 1201 L 567 1202 L 580 1202 L 581 1203 L 601 1203 L 602 1204 L 672 1203 L 673 1202 L 698 1201 L 699 1200 L 708 1200 L 709 1199 L 717 1199 L 718 1198 L 746 1195 L 747 1194 L 758 1193 L 764 1191 L 769 1191 L 778 1188 L 782 1188 L 787 1186 L 803 1183 L 832 1174 L 855 1164 L 860 1160 L 860 1067 L 861 1066 L 862 1067 L 860 1065 L 860 963 L 882 944 L 896 929 L 909 912 L 919 896 L 930 873 L 938 850 L 943 829 L 945 810 L 946 809 L 946 800 L 947 799 L 948 745 L 947 744 L 947 722 L 946 721 L 945 695 L 944 694 L 942 663 L 941 662 L 941 654 L 940 653 L 940 646 L 939 645 L 939 637 L 938 636 L 935 605 L 934 604 L 934 598 L 933 597 L 933 591 L 931 584 L 931 578 L 930 577 L 930 571 L 929 570 L 926 547 L 927 546 L 941 560 L 942 556 L 938 543 L 938 539 L 934 523 L 926 498 L 926 495 L 912 455 L 901 431 L 901 429 L 887 401 L 877 384 L 860 361 L 844 345 L 832 336 L 817 328 L 801 323 L 791 322 L 790 321 L 778 321 L 777 320 L 751 321 L 750 322 L 736 323 L 735 324 L 731 324 L 730 325 L 709 329 L 685 337 L 680 340 L 671 343 L 663 348 L 661 348 L 647 356 L 632 366 L 628 370 L 626 370 L 603 354 L 580 342 L 578 342 L 563 335 L 533 326 L 512 323 L 511 322 L 504 322 L 503 321 L 476 320 L 475 321 L 463 321 L 462 322 L 452 323 Z" fill="#FDE2C4"/>
<!-- Brows remain independent for animation -->
<g id="brows">
<path id="brow-left" class="anim-part" d="M 347 555 L 348 555 L 364 540 L 365 540 L 369 536 L 370 536 L 373 533 L 374 533 L 382 527 L 396 520 L 398 520 L 404 517 L 407 517 L 408 516 L 410 516 L 411 515 L 415 515 L 416 514 L 420 514 L 421 513 L 431 513 L 432 512 L 444 512 L 445 513 L 455 513 L 456 514 L 462 514 L 463 515 L 467 515 L 468 516 L 477 517 L 478 518 L 485 519 L 489 521 L 492 521 L 493 522 L 507 526 L 510 528 L 515 529 L 523 533 L 525 533 L 539 540 L 541 540 L 548 544 L 550 544 L 563 551 L 568 552 L 573 549 L 579 543 L 588 527 L 588 525 L 590 522 L 590 519 L 591 518 L 591 514 L 592 513 L 592 501 L 591 500 L 591 497 L 588 491 L 586 489 L 584 485 L 580 481 L 580 480 L 572 472 L 571 472 L 563 465 L 550 458 L 549 458 L 549 459 L 550 460 L 550 462 L 552 466 L 552 470 L 553 471 L 553 474 L 552 475 L 522 460 L 517 459 L 514 457 L 512 457 L 509 455 L 507 455 L 503 453 L 500 453 L 496 451 L 493 451 L 492 450 L 489 450 L 488 449 L 485 449 L 484 448 L 481 448 L 480 447 L 468 446 L 467 445 L 460 445 L 459 444 L 434 444 L 433 445 L 427 445 L 426 446 L 417 447 L 416 448 L 408 450 L 403 453 L 401 453 L 386 462 L 370 477 L 370 478 L 366 482 L 366 483 L 362 488 L 361 491 L 359 493 L 356 499 L 356 501 L 352 509 L 351 515 L 350 516 L 350 519 L 349 520 L 348 531 L 347 532 Z" fill="#F96001"/>
<path id="brow-right" class="anim-part" d="M 907 550 L 907 537 L 906 536 L 906 527 L 905 526 L 905 521 L 904 520 L 903 513 L 902 512 L 901 507 L 899 504 L 899 502 L 889 484 L 880 474 L 880 473 L 866 461 L 865 461 L 860 457 L 848 451 L 846 451 L 843 449 L 841 449 L 837 447 L 833 447 L 832 446 L 828 446 L 827 445 L 821 445 L 820 444 L 796 444 L 795 445 L 787 445 L 786 446 L 780 446 L 779 447 L 770 448 L 769 449 L 758 451 L 751 454 L 748 454 L 747 455 L 742 456 L 739 458 L 737 458 L 734 460 L 727 462 L 702 475 L 701 474 L 701 469 L 702 468 L 702 465 L 705 458 L 704 458 L 692 464 L 689 467 L 684 470 L 672 482 L 672 483 L 667 489 L 663 497 L 663 500 L 662 501 L 662 514 L 663 515 L 663 519 L 664 520 L 665 526 L 674 542 L 683 551 L 685 551 L 686 552 L 691 551 L 708 542 L 710 542 L 726 534 L 728 534 L 731 532 L 733 532 L 736 530 L 741 529 L 744 527 L 746 527 L 752 524 L 755 524 L 756 523 L 758 523 L 765 520 L 768 520 L 772 518 L 776 518 L 777 517 L 780 517 L 781 516 L 791 515 L 792 514 L 798 514 L 799 513 L 810 513 L 811 512 L 823 512 L 824 513 L 832 513 L 833 514 L 838 514 L 839 515 L 842 515 L 843 516 L 846 516 L 847 517 L 852 518 L 855 520 L 857 520 L 860 522 L 862 522 L 866 524 L 868 526 L 871 527 L 873 529 L 876 530 L 878 532 L 882 534 L 886 538 L 887 538 L 891 542 L 892 542 L 905 555 L 906 555 L 906 551 Z" fill="#F96001"/>
</g>
<g id="eyes">
<g id="eye-l"><ellipse cx="478" cy="612" rx="68" ry="52" fill="#fff"/><circle id="pupil-l" cx="478" cy="612" r="27" fill="#150a04"/><circle class="shine" cx="470" cy="602" r="8" fill="#fff"/></g>
<g id="eye-r"><ellipse cx="796" cy="612" rx="68" ry="52" fill="#fff"/><circle id="pupil-r" cx="796" cy="612" r="27" fill="#150a04"/><circle class="shine" cx="788" cy="602" r="8" fill="#fff"/></g>
</g>
<!-- Facial hair -->
<path id="moustache" class="anim-part" d="M 353 768 L 354 779 L 361 795 L 374 809 L 349 839 L 359 844 L 372 845 L 373 846 L 373 857 L 374 858 L 374 862 L 375 863 L 375 866 L 378 875 L 382 883 L 389 893 L 399 903 L 404 906 L 405 897 L 408 888 L 414 878 L 422 870 L 423 871 L 423 876 L 424 877 L 424 882 L 425 883 L 426 889 L 434 902 L 440 891 L 449 879 L 469 859 L 494 841 L 517 829 L 519 829 L 524 826 L 534 823 L 537 821 L 552 816 L 559 815 L 563 813 L 574 811 L 589 806 L 592 804 L 594 804 L 615 792 L 627 781 L 640 793 L 657 803 L 659 803 L 662 805 L 664 805 L 667 807 L 679 811 L 682 811 L 686 813 L 701 816 L 722 823 L 732 828 L 734 828 L 761 842 L 781 856 L 801 875 L 810 886 L 816 895 L 819 902 L 822 899 L 828 887 L 829 879 L 830 878 L 830 870 L 831 869 L 841 880 L 842 883 L 844 885 L 848 895 L 850 906 L 858 900 L 867 890 L 876 874 L 876 872 L 878 869 L 879 862 L 880 861 L 881 846 L 882 845 L 894 844 L 900 842 L 905 839 L 896 830 L 880 809 L 880 808 L 888 801 L 893 794 L 899 781 L 899 778 L 900 777 L 900 769 L 901 768 L 899 768 L 895 771 L 893 771 L 884 775 L 867 776 L 866 775 L 861 775 L 860 774 L 853 773 L 847 770 L 845 770 L 823 758 L 817 753 L 825 745 L 831 734 L 833 728 L 834 718 L 822 724 L 812 726 L 811 727 L 807 727 L 806 728 L 793 728 L 792 727 L 783 726 L 774 722 L 772 722 L 760 716 L 742 704 L 734 700 L 729 696 L 711 687 L 702 684 L 695 683 L 694 682 L 690 682 L 689 681 L 666 681 L 665 682 L 656 683 L 638 690 L 630 695 L 627 698 L 624 695 L 609 687 L 607 687 L 601 684 L 594 683 L 593 682 L 589 682 L 588 681 L 564 681 L 563 682 L 555 683 L 543 687 L 530 693 L 492 717 L 471 726 L 461 727 L 460 728 L 449 728 L 448 727 L 443 727 L 442 726 L 438 726 L 432 724 L 420 718 L 420 724 L 421 725 L 421 729 L 423 735 L 428 744 L 432 749 L 437 753 L 429 759 L 411 769 L 393 775 L 376 776 L 375 775 L 366 774 Z" fill="#F96001"/>
<path id="beard" class="anim-part" d="M 627 871 L 614 894 L 601 911 L 584 929 L 562 947 L 556 951 L 555 950 L 556 946 L 559 941 L 559 939 L 568 922 L 555 928 L 553 930 L 542 935 L 535 940 L 530 942 L 525 946 L 516 951 L 503 961 L 487 977 L 481 986 L 476 998 L 475 1007 L 474 1008 L 474 1018 L 475 1019 L 475 1024 L 477 1029 L 481 1021 L 491 1011 L 493 1012 L 492 1014 L 492 1019 L 491 1020 L 490 1035 L 491 1036 L 491 1044 L 492 1045 L 492 1050 L 493 1051 L 494 1058 L 502 1077 L 515 1096 L 525 1106 L 534 1113 L 534 1110 L 532 1105 L 532 1101 L 531 1100 L 531 1083 L 532 1082 L 546 1103 L 561 1118 L 592 1141 L 605 1152 L 615 1162 L 627 1178 L 636 1165 L 654 1147 L 676 1130 L 680 1128 L 703 1108 L 713 1096 L 721 1082 L 723 1085 L 723 1099 L 722 1100 L 722 1105 L 720 1109 L 720 1112 L 725 1109 L 736 1099 L 744 1089 L 751 1078 L 755 1070 L 755 1068 L 757 1065 L 761 1053 L 762 1043 L 763 1042 L 763 1020 L 762 1019 L 762 1014 L 761 1012 L 762 1011 L 764 1012 L 771 1019 L 777 1029 L 779 1023 L 779 1015 L 780 1014 L 778 999 L 772 985 L 764 974 L 753 963 L 743 955 L 720 940 L 686 922 L 699 950 L 698 951 L 686 943 L 674 933 L 650 908 L 636 888 Z" fill="#F96001"/>
</g>
</svg>
</div>
<div class="cap top" id="cap-top"></div>
<div class="cap bot" id="cap-bot"></div>
</div>
<nav class="bar">
<div class="bar-grid">
<button id="reroll" type="button" class="wide">reroll caption</button>
<button id="save" type="button">save png</button>
<button id="share" type="button">share</button>
</div>
</nav>
</div>
<script src="captions.js?v=6"></script>
<script>
(function () {
'use strict';
const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
const $ = (id) => document.getElementById(id);
const r = (a, b) => Math.random() * (b - a) + a;
const ri = (a, b) => Math.round(r(a, b));
const sgn = () => Math.random() < 0.5 ? 1 : -1;
const pick = (a) => a[Math.floor(Math.random() * a.length)];
/* ---- title marquee (paused when tab hidden) ---- */
const t = 'gunterlie ';
let ti = 0;
setInterval(() => { if (!document.hidden) { document.title = (t + t).slice(ti, ti + 16); ti = (ti + 1) % t.length; } }, 180);
/* ---- floating words ---- */
const words = ["gunterlie", "gunterlie", "gunterlie", "gunterlie", "gunterlie", "gunterlie", "slurp", "slurp slurp", "orange", "what did you expect?", "based", "no regressions", "ship it", "touch grass", "it's dns", "lgtm", "vibes", "sudo", "git push --force", "404", "kernel panic", "segfault", "merge conflict", "skill issue", "ratio", "cope", "seethe", "mald", "gigachad", "sigma", "npc", "main character", "w", "l", "fr fr", "no cap", "bussin", "rizz", "sus", "poggers", "kekw", "monke", "stonks", "this is fine", "press f", "ok boomer", "big brain", "galaxy brain", "chef's kiss", "mustache.exe", "beard.dll", "orange.sh", "rm -rf /", "ctrl+z", "alt+f4", "hello world", "undefined", "NaN", "null", "TODO", "FIXME", "works on my machine", "one more commit", "it's friday", "sleep.exe not found", "orange man", "smug", "chaos", "memes", "lore", "canon", "banger", "cursed", "blessed", "unhinged", "feral", "goblin mode", "crab rave", "nyan", "doge", "wow", "such orange", "very meme", "much slurp","vibe coding","vibes only","accept all","you're absolutely right","let me fix that","one more prompt","tab tab tab","looks good to me","trust the vibes","no tests","ship the vibe","10x dev","prompt: make it pretty","i don't read diffs","it just works","agent go brrr","context full","rebase? vibes","git commit -am fix"];
const emojis = ["🍊", "🔥", "💀", "🗿", "🦆", "🐸", "🥕", "🧡", "🚧", "📦", "🐧", "🤡", "👁️", "🫠", "🧃", "🪩", "🛸", "🌋", "🦀", "🐙", "🥭", "🍑", "⚡", "💥", "🎃", "🦊", "🐯", "🧨"];
const stage = document.querySelector('.stage'), floats = $('floats');
const frag = document.createDocumentFragment();
for (let i = 0; i < 150; i++) {
const layer = Math.random();
let size, opacity, dur;
if (layer < 0.35) { size = r(.45,.7); opacity = r(.03,.07); dur = ri(32,48); }
else if (layer < 0.60) { size = r(.7,1.1); opacity = r(.06,.13); dur = ri(22,34); }
else if (layer < 0.80) { size = r(1.1,1.8); opacity = r(.10,.2); dur = ri(16,26); }
else { size = r(1.8,3.0); opacity = r(.14,.32); dur = ri(12,20); }
const el = document.createElement('span');
el.className = 'float';
const emo = Math.random() < .18; el.textContent = emo ? pick(emojis) : pick(words);
if (emo) { size *= 1.6; opacity = Math.min(opacity * 1.4, .4); }
el.style.cssText = `top:${r(0,98)}%;left:${r(-2,92)}%;font-size:${size.toFixed(2)}rem;opacity:${opacity.toFixed(2)};--dx:${sgn()*ri(6,28)}px;--dy:${sgn()*ri(6,28)}px;--dr:${sgn()*ri(2,14)}deg;animation-duration:${dur}s;animation-delay:-${ri(0,dur)}s`;
frag.appendChild(el);
}
floats.appendChild(frag);
setTimeout(() => $('tagline').classList.add('hidden'), 6000);
/* ---- ticker rows (scrolling meme tape) ---- */
const tape = ['slurp slurp slurp','what did you expect?','no regressions','ship it on friday','it was dns','orange orange orange','touch grass (later)','skill issue','gunterlie approves','merge to main and pray','vibes only','404 sleep not found','one more commit','based and orange-pilled','chaos is a ladder','the mustache sees all','vibe coding is a lifestyle','accept all changes','you are absolutely right','one more prompt','i never read the diff','tab tab tab tab','make it pretty','it works, do not ask why','ship the vibes','the agent said done'];
for (let n = 0; n < 4; n++) {
const row = document.createElement('div');
row.className = 'tape' + (n % 2 ? ' rev' : '');
row.style.top = (8 + n * 24 + r(-3, 3)) + '%';
row.style.animationDuration = ri(55, 95) + 's';
const line = Array.from({ length: 8 }, () => pick(tape)).join(' ✦ ');
row.textContent = line + ' ✦ ' + line;
floats.appendChild(row);
}
/* ---- random fly-bys ---- */
function flyby() {
if (document.hidden) return;
const el = document.createElement('div');
const emo = Math.random() < .5;
el.className = 'flyby';
el.textContent = emo ? pick(emojis) : pick(words);
const fromLeft = Math.random() < .5, y = r(8, 88), dur = ri(5, 10) * 1000;
el.style.top = y + '%'; el.style.fontSize = (emo ? r(2.4, 5) : r(1, 2.2)) + 'rem';
floats.appendChild(el);
const a = el.animate([
{ transform: `translateX(${fromLeft ? '-20vw' : '120vw'}) rotate(0deg)`, opacity: 0 },
{ opacity: .55, offset: .1 }, { opacity: .55, offset: .9 },
{ transform: `translateX(${fromLeft ? '120vw' : '-20vw'}) rotate(${sgn() * ri(180, 720)}deg)`, opacity: 0 },
], { duration: dur, easing: 'linear' });
a.onfinish = () => el.remove();
}
if (!reduced) { setTimeout(flyby, 1500); (function loop() { flyby(); setTimeout(loop, r(2500, 6500)); })(); }
/* ---- fake status log ---- */
const logLines = ['orange levels: nominal','slurp buffer: 87%','mustache integrity: ok','smug engine: running','vibes: immaculate','memes in queue: 9001','regressions: 0 (suspicious)','touching grass: postponed','dns: blamed','coffee: critical','chaos: stable','beard.dll loaded','sleep: not found','uptime: questionable','brain: rebooting','skill issue detected','eyebrows: raised','gunterlie: online','vibes: committed unread','diff reviewed: no','accept all: enabled','prompt budget: ???','agent said done: unverified','context window: 98%'];
const log = $('log'); let li = 0;
function pushLog() {
const d = document.createElement('div'); d.textContent = '> ' + pick(logLines);
log.appendChild(d); while (log.children.length > 4) log.firstChild.remove(); li++;
}
pushLog(); setInterval(pushLog, 2800);
/* ---- eyes follow the pointer ---- */
const face = $('face'), avatar = $('avatar');
const eyes = [
{ pupil: $('pupil-l'), shine: null, cx: 478, cy: 612 },
{ pupil: $('pupil-r'), shine: null, cx: 796, cy: 612 },
];
let aim = { x: 0, y: 0 }, wander = true;
function lookAt(clientX, clientY) {
const b = avatar.getBoundingClientRect();
const dx = clientX - (b.left + b.width / 2), dy = clientY - (b.top + b.height / 2);
const d = Math.hypot(dx, dy) || 1, k = Math.min(1, d / (b.width * .6));
aim = { x: dx / d * k, y: dy / d * k };
wander = false; clearTimeout(lookAt.t); lookAt.t = setTimeout(() => wander = true, 3500);
applyAim();
}
function applyAim() {
for (const e of eyes) {
e.pupil.setAttribute('cx', e.cx + aim.x * 30);
e.pupil.setAttribute('cy', e.cy + aim.y * 22);
}
}
addEventListener('pointermove', (e) => lookAt(e.clientX, e.clientY), { passive: true });
setInterval(() => { if (wander && !reduced) { aim = { x: r(-1,1), y: r(-.6,.6) }; applyAim(); } }, 1600);
(function blinkLoop() { face.classList.add('blink'); setTimeout(() => face.classList.remove('blink'), 110); setTimeout(blinkLoop, r(2200, 5200)); })();
/* ---- captions ---- */
let cur = window.makeCaption();
function setCaption(c) { cur = c; $('cap-top').textContent = c[0]; $('cap-bot').textContent = c[1]; }
function reroll() { let c; do { c = window.makeCaption(); } while (c[0] === cur[0] && c[1] === cur[1]); setCaption(c); }
setCaption(cur);
$('reroll').addEventListener('click', reroll);
/* ---- click tricks ---- */
let busy = false, clicks = 0;
const anims = [
[[{transform:'rotate(0)'},{transform:'rotate(360deg)'}], 600],
[[{transform:'rotate(0)'},{transform:'rotate(-18deg)'},{transform:'rotate(14deg)'},{transform:'rotate(-8deg)'},{transform:'rotate(0)'}], 700],
[[{transform:'translateY(0) scale(1)'},{transform:'translateY(-14%) scale(1.08)'},{transform:'translateY(4%) scale(.96)'},{transform:'translateY(0) scale(1)'}], 600],
[[{transform:'rotateY(0)'},{transform:'rotateY(360deg)'}], 700],
[[{transform:'translateX(0) skewX(0)'},{transform:'translateX(-4%) skewX(8deg)'},{transform:'translateX(4%) skewX(-8deg)'},{transform:'translateX(0) skewX(0)'}], 450],
[[{transform:'scale(1)'},{transform:'scale(.4)'},{transform:'scale(1.12)'},{transform:'scale(1)'}], 520],
[[{transform:'translateX(0)'},{transform:'translateX(-6%)'},{transform:'translateX(6%)'},{transform:'translateX(-4%)'},{transform:'translateX(0)'}], 400],
[[{transform:'rotate(0) scale(1)'},{transform:'rotate(-25deg) scale(1.1)'},{transform:'rotate(18deg) scale(.95)'},{transform:'rotate(0) scale(1)'}], 800],
];
const brows = ['brow-left','brow-right'].map($);
function poke() {
clicks++;
if (busy) return;
busy = true;
const surprise = Math.random() < .3;
if (surprise) {
const e = $('eye-l').parentNode;
e.animate([{transform:'scale(1)'},{transform:'scale(1.25)'},{transform:'scale(1)'}], { duration: 500 });
brows.forEach((b) => b.animate([{transform:'translateY(0)'},{transform:'translateY(-40px)'},{transform:'translateY(0)'}], { duration: 500 }));
}
if (clicks % 5 === 0) reroll();
if (reduced) { busy = false; return; }
const [kf, ms] = pick(anims);
face.animate(kf, { duration: ms, easing: 'ease-out' }).onfinish = () => { busy = false; };
}
avatar.addEventListener('click', poke);
avatar.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); poke(); } });
/* ---- konami ---- */
const code = ['ArrowUp','ArrowUp','ArrowDown','ArrowDown','ArrowLeft','ArrowRight','ArrowLeft','ArrowRight','b','a'];
let ki = 0;
addEventListener('keydown', (e) => {
ki = (e.key.toLowerCase() === code[ki].toLowerCase()) ? ki + 1 : (e.key === code[0] ? 1 : 0);
if (ki === code.length) { ki = 0; document.body.classList.toggle('party'); }
});
/* ---- save as png ---- */
function wrap(ctx, text, maxW) {
const out = []; let line = '';
for (const w of text.split(' ')) { const t2 = line ? line + ' ' + w : w; if (ctx.measureText(t2).width > maxW && line) { out.push(line); line = w; } else line = t2; }
out.push(line); return out;
}
function renderMeme() {
return new Promise((resolve, reject) => {
const svg = face.querySelector('svg').cloneNode(true);
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svg.setAttribute('width', 1254); svg.setAttribute('height', 1254);
const bg = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
bg.setAttribute('width', 1254); bg.setAttribute('height', 1254); bg.setAttribute('fill', '#1d0d05');
svg.insertBefore(bg, svg.firstChild);
const img = new Image();
img.onerror = reject;
img.onload = () => {
const S = 1254, c = document.createElement('canvas'); c.width = c.height = S;
const ctx = c.getContext('2d'); ctx.drawImage(img, 0, 0, S, S);
ctx.font = '900 112px Impact, "Arial Black", sans-serif'; ctx.textAlign = 'center'; ctx.lineJoin = 'round';
ctx.lineWidth = 12; ctx.strokeStyle = '#000'; ctx.fillStyle = '#fff';
const draw = (text, y, dir) => { const ls = wrap(ctx, text.toUpperCase(), S * .92); ls.forEach((l, i) => { const yy = dir > 0 ? y + i * 118 : y - (ls.length - 1 - i) * 118; ctx.strokeText(l, S / 2, yy); ctx.fillText(l, S / 2, yy); }); };
draw(cur[0], 130, 1); draw(cur[1], S - 50, -1);
ctx.font = '700 28px "Space Mono", monospace'; ctx.fillStyle = 'rgba(255,255,255,.55)'; ctx.textAlign = 'right'; ctx.fillText('gunterlie.de', S - 24, S - 8);
c.toBlob((b) => b ? resolve(b) : reject(new Error('toBlob failed')), 'image/png');
};
img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(new XMLSerializer().serializeToString(svg));
});
}
function download(blob) {
const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'gunterlie-meme.png'; a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 2000);
}
function flash(btn, text) { const old = btn.dataset.label || (btn.dataset.label = btn.textContent); btn.textContent = text; setTimeout(() => { btn.textContent = old; }, 1600); }
$('save').addEventListener('click', () => { renderMeme().then(download).catch(() => {}); });
$('share').addEventListener('click', async () => {
const btn = $('share');
try {
const blob = await renderMeme();
const file = new File([blob], 'gunterlie-meme.png', { type: 'image/png' });
if (navigator.canShare && navigator.canShare({ files: [file] })) {
await navigator.share({ files: [file], title: 'gunterlie', url: 'https://gunterlie.de' });
} else if (navigator.clipboard && window.ClipboardItem) {
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]);
flash(btn, 'copied!');
} else {
download(blob); flash(btn, 'saved');
}
} catch (err) {
if (err && err.name === 'AbortError') return;
try { download(await renderMeme()); flash(btn, 'saved'); } catch (e) { flash(btn, 'failed'); }
}
});
})();
</script>
</body>
</html>