GodUIGodUI
129Follow on X

Anatomy of the GodUI Skeleton

Why a sliding band replaces the pulse, how it moves with translate only, and what reduced motion gets instead.

01/03A band, not a gradient
tsx
"relative overflow-hidden rounded-md bg-accentafter:absolute after:inset-0 after:-translate-x-fullafter:bg-linear-to-r after:from-transparentafter:via-foreground/[0.06] after:to-transparentafter:animate-godui-shimmer …"@keyframes godui-shimmer {to { translate: 100% 0; }}/* 1.6s, cubic-bezier(0.65, 0, 0.35, 1), infinite */
01

A band, not a gradient

The usual shimmer paints a wide gradient and animates background-position. That repaints the element every frame.

GodUI paints the gradient once. It lives on an ::after layer that covers the block, and the layer starts one full width to the left (-translate-x-full), fully outside it. The animation moves it to one full width to the right, so the band enters through the left edge and leaves through the right (under dir="rtl" the loop plays in reverse, right to left; the curve is symmetric, so it eases the same way). The block is overflow-hidden, which clips whatever is outside it. Only translate changes, so the layer is promoted once and the compositor slides it.

The band is foreground at 6% opacity on the accent fill, which keeps it readable in both themes without turning the placeholder into a flash. This scene slows the loop to 3s so you can follow it.

02/03Reduced motion falls back to pulse
tsx
"… motion-reduce:animate-pulse motion-reduce:after:hidden"
02

Reduced motion falls back to pulse

A sweeping band is still movement across the whole block. For prefers-reduced-motion, motion-reduce:after:hidden removes the band and motion-reduce:animate-pulse puts back shadcn's original fade: no travel, just an opacity change. The scene shows that pulse.

03/03Result
03

The result

Each block carries its own band and runs the same 1.6s loop from the moment it mounts. Blocks that mount together stay in step; one that mounts later runs the same loop, offset by when it arrived.

What's animated

InteractionKeyframe / mechanismPropertiesEasingDuration
Shimmergodui-shimmertranslatecubic-bezier(0.65, 0, 0.35, 1) (ease-in-out)1.6s loop

Under dir="rtl" the loop plays in reverse, so the band sweeps right to left.

Why GPU-only

The band is a single ::after layer and the loop changes translate, nothing else. Layout and paint stay out of it, however many skeletons are on screen.

Reduced motion

motion-reduce:after:hidden removes the band and motion-reduce:animate-pulse restores shadcn's opacity pulse, so the placeholder still reads as busy without a sweep. As in shadcn, className="animate-none" stops it: no band, and no pulse under reduced motion either.

Replacing shadcn

npx shadcn add @godui/skeleton overwrites components/ui/skeleton.tsx. Exports, props and data-slot attributes match shadcn/ui new-york-v4, so existing imports keep working. It also installs godui-motion (easings, keyframes, the FLIP hook) into your project, plus the godui-shimmer keyframe.

One class changes meaning: the block is now relative overflow-hidden so it can clip the band. A call site's absolute or fixed still wins, because the classes go through cn.