Anatomy of the GodUI Skeleton
Why a sliding band replaces the pulse, how it moves with translate only, and what reduced motion gets instead.
↓Scroll to step through it
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.
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.
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.
"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 */Anatomy of the GodUI Skeleton
Why a sliding band replaces the pulse, how it moves with translate only, and what reduced motion gets instead.
"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 */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.
"… motion-reduce:animate-pulse motion-reduce:after:hidden"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.
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
| Interaction | Keyframe / mechanism | Properties | Easing | Duration |
|---|---|---|---|---|
| Shimmer | godui-shimmer | translate | cubic-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.