Keyframe animations for cards, icons, loaders and headings - drop a class on an element and it comes alive.
1Typewriter
Types a single line of monospace text letter by letter with a blinking caret; set --fx-ch to the character count. Class: fx-typewriter
terminal
Hello, world.<div class="flex flex-wrap items-center justify-center gap-4 p-4 h-full" style="min-height:200px">
<div class="bg-dark text-white rounded-lg p-4 w-full" style="max-width:18rem">
<div class="small text-white/50 mb-1">
terminal
</div>
<span class="fx-typewriter" style="--fx-ch:13">Hello, world.</span>
</div>
</div>
/* CSS (already in assets/css/effects.css) */
.fx-typewriter {
display: inline-block; max-width: 100%; overflow: hidden; white-space: nowrap; vertical-align: bottom;
font-family: var(--ui-font-monospace, monospace);
width: calc(var(--fx-ch, 20) * 1ch + .15em);
border-right: .12em solid var(--wt-primary);
animation: fx-typewriter-type 4.5s steps(var(--fx-ch, 20)) infinite, fx-typewriter-caret .8s step-end infinite;
}
@keyframes fx-typewriter-type { 0% { width: 0; } 65%, 100% { width: calc(var(--fx-ch, 20) * 1ch + .15em); } }
@keyframes fx-typewriter-caret { 50% { border-color: transparent; } }
@media (prefers-reduced-motion: reduce) {
.fx-typewriter, .fx-typewriter::before, .fx-typewriter::after, .fx-typewriter *, .fx-typewriter *::before, .fx-typewriter *::after { animation: none !important; transition: none !important; }
}2Shimmer Skeleton
Loading placeholders with a light sweep; add the class to every grey block of a skeleton card. Class: fx-shimmer-skeleton
<div class="flex flex-wrap items-center justify-center gap-4 p-4 h-full" style="min-height:200px">
<div class="card w-full" style="max-width:18rem" aria-busy="true" aria-label="Loading content">
<div class="card-body">
<div class="flex items-center gap-4 mb-4">
<span class="fx-shimmer-skeleton rounded-full shrink-0" style="width:48px;height:48px"></span>
<div class="grow">
<span class="fx-shimmer-skeleton mb-2" style="width:70%"></span><span class="fx-shimmer-skeleton" style="width:45%"></span>
</div>
</div>
<span class="fx-shimmer-skeleton mb-2" style="height:70px"></span> <span class="fx-shimmer-skeleton mb-2"></span> <span class="fx-shimmer-skeleton" style="width:60%"></span>
</div>
</div>
</div>
/* CSS (already in assets/css/effects.css) */
.fx-shimmer-skeleton {
display: block; min-height: .9rem; border-radius: var(--wt-radius, .5rem);
background: linear-gradient(90deg, rgba(var(--wt-primary-rgb), .08) 25%, rgba(var(--wt-primary-rgb), .22) 37%, rgba(var(--wt-primary-rgb), .08) 63%);
background-size: 400% 100%;
animation: fx-shimmer-skeleton-shine 1.4s ease infinite;
}
@keyframes fx-shimmer-skeleton-shine { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
.fx-shimmer-skeleton, .fx-shimmer-skeleton::before, .fx-shimmer-skeleton::after, .fx-shimmer-skeleton *, .fx-shimmer-skeleton *::before, .fx-shimmer-skeleton *::after { animation: none !important; transition: none !important; }
}