animated logo - nberlette.svg
Animated personal logomark with the Ukrainian flag colors. SVG and CSS.
by Nicholas Berlette
HTML
<script src="https://unpkg.com/windicss-runtime-dom"></script>
<!-- start emblem -->
<div class="bg-inherit min-w-screen min-h-screen w-full h-screen m-0 p-12 relative" style="box-shadow:0 -3rem 15rem -2rem inset #0009;">
<div class="flex flex-col place-items-center justify-around items-center align-center text-center absolute top-1/2 -translate-y-1/2 left-1/2 transform -translate-x-1/2">
<div class="w-auto h-[60vh] <md:w-[80vw] max-w-[80vw] max-h-[50vh]">
<div class="hover:animate__jello animate__animated transform hover:animate__infinite">
<svg viewBox="-20 -20 140 140" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" class="fill-none stroke-current stroke-0 text-inherit group transform animate__flipInY animate__animated animate__repeat-1 hover:animate__wobble hover:animate__infinite hover:animate__delay-0s" style="animation-delay:1s;" id="nb-emblem">
<g id="nb">
<circle cx="50" cy="50" r="50" class="stroke-current fill-transparent outer-circle" id="c-o" />
<circle cx="50" cy="50" r="40" class="stroke-current fill-transparent inner-circle" id="c-i" />
<path d="M34.5,31 l0,38 l8,0 l0,-24 l15,24 l8,0 l0,-38 l-8,0 l0,24 l-15,-24 Z" fill="transparent" class="letter-n text-inherit group-hover:animate-pulse" id="n-b" />
</g>
<use href="#b" />
<g id="ukraine-overlay">
<path fill="#044bbb" d="M-571-473H662v822H-571z" clip-path="url(#a)" />
<path fill="#ffc500" d="M-571 50H662v411H-571z" clip-path="url(#a)" />
<clipPath id="a"><use href="#n-b" overflow="visible"/></clipPath>
</g>
</svg>
</div>
</div>
<!-- end emblem -->
<header>
<h1 class="animate__animate animate__backInDown animate__delay-3s animate__repeat-1 transform text-6xl font-[Metropolis] font-thin lowercase tracking-tighter">@nberlette</h1>
<h2 class="animate__animate animate__backInUp transform text-3xl font-[Metropolis] font-thin lowercase tracking-tight">Fullstack...
CSS
/* @import "https://unpkg.com/[email protected]/animate.css"; */
@import "https://unpkg.com/@typehaus/[email protected]/700.css";
@import "https://unpkg.com/@typehaus/[email protected]/100.css";
/* all emblems */
[id^="nb-emblem"] {
cursor: wait;
}
[id^="nb-emblem"] .letter-n {
stroke-width: 1;
transform-origin: 35.75% 35.75%;
}
[id^="nb-emblem"]:hover .letter-n {
fill: black;
animation-play-state: running;
}
[id^="nb-emblem"] .inner-circle {
stroke-width: 4;
transform-origin: 35.75% 35.75%;
}
[id^="nb-emblem"] .outer-circle {
stroke-width: 2;
transform-origin: 35.75% 35.75%;
}
:is(h1, h2, h3) {
font-family: 'Metropolis', 'Inter', sans-serif !important;
cursor: default;
margin:0;
padding:0;
}
h1 {
margin-bottom: 1rem;
padding: 1rem 1rem 1rem 0.5rem;
border-bottom: 1px dashed #fcc50044;
}
h1 + h2 {
margin-top: 0.666em;
}
#nb-emblem {
/* transition: transform 0.5s 1s ease-in, opacity 0.666s 1.1s ease-in; */
/* transform-origin: 50% 100%; */
/* transform: perspective(500px) scale3d(var(--tw-scale-x, 0), var(--tw-scale-y, 0), var(--tw-scale-z, 1)); */
/* opacity: 0; */
filter: drop-shadow(0 0.1rem 0.2rem #0003);
}
#ukraine-overlay {
transition: 0.5s fill 1.5s ease-in;
}
/* #ukraine-overlay path {
fill: #044bbb;
transition: inherit !important;
} */
#ukraine-overlay path:last-child {
fill: #ffc500;
transition: 0.5s fill 2s ease-in, 0.6 transform 3s ease-in !important;
}
/* emblem #1 */
#nb-emblem .letter-n {
fill: #044bbb;
transition: fill 2.5s ease-out, stroke 1s 3s;
stroke: #ffc50066;
}
#nb-emblem:hover .letter-n {
animation-play-state: running;
stroke: #ffc500cc;
}
#nb-emblem .inner-circle {
transition: stroke-width 6s, transform 2s, stroke 1.33s 2.5s ease-in;
}
#nb-emblem:hover .inner-circle {
stroke: #003aaa;
stroke-width: 10 !important;
transform: scale(1.1);
}
#nb-emblem .outer-circle {
stroke-dasharray: 20 4;
stroke-dashoffset: 20;
stroke-opacity: 0.5;
transition:...
JavaScript
const resources = [
{ type: 'module', prefetch: true, url: 'https://unpkg.com/windicss-runtime-dom' },
{ type: 'stylesheet', prefetch: true, url: 'https://unpkg.com/@typehaus/metropolis@latest/100.css' },
{ type: 'stylesheet', prefetch: true, url: 'https://unpkg.com/@typehaus/metropolis@latest/300.css' },
{ type: 'stylesheet', prefetch: true, url: 'https://unpkg.com/@typehaus/metropolis@latest/500.css' },
{ type: 'stylesheet', prefetch: true, url: 'https://cdn.jsdelivr.net/npm/@typehaus/metropolis@latest/700.css' },
{ type: 'icon', prefetch: true, url: 'https://cdn.berlette.com/brand/logo.svg' }
];
let hosts = [...new Set(resources.map(r => r.url.startsWith('http') && (new URL(r.url).origin)).filter(Boolean))]
const preconnects = hosts.flatMap(href =>
['preconnect', 'prefetch-dns'].flatMap(rel =>
`<link rel="${rel}" href="${href}" />`
))
const [prefetches, stylesheets] = resources
.filter(r => r.type.startsWith('style'))
.reduce((a, c) => [
[...a[0], ...(c.prefetch ? [`<link rel="prefetch" as="style" type="text/css;charset=utf-8" href="${c.url}" ${c.url.startsWith('http') ? 'crossorigin="anonymous" ' : ''}/>`] : [])],
[...a[1], `<link rel="stylesheet" type="text/css;charset=utf-8" href="${c.url}" ${c.url.startsWith('http') ? 'crossorigin="anonymous" ' : ''}/>`],
], [[], []])
console.log(hosts)
console.log(preconnects)
console.log(prefetches)
console.log(stylesheets)