Everything is a CSS custom property, so one skeleton can differ from the page:

variabledefaultwhat
--skullet-basergb(128 128 128 / 0.2) in light, rgb(255 255 255 / 0.09) in darkthe bars
--skullet-highlightrgb(255 255 255 / 0.75) in light, rgb(255 255 255 / 0.16) in darkthe shimmer's band
--skullet-radius0.25emhow round each bar is
--skullet-hold150mshow long a skeleton waits before showing, so fast data never shows one
--skullet-fade200msthe crossfade at the reveal
--skullet-resize280msthe height ease when the real content is a different size
--skullet-cascade320mshow long a sequence — or smart's cascade — takes from first piece to last
--skullet-delay0msa pause before the reveal starts
--skullet-secondary-delay60mshow long small text trails the heading it sits under
--skullet-enter-filternonewhere pieces come from: e.g. blur(6px)
--skullet-enter-scale1where pieces come from: e.g. 0.98
--skullet-animationshimmershimmer, group-shimmer, pulse or none
--skullet-speedslowslow or fast
--skullet-text-topascenderascender, cap-height or x-height — where each line's bar starts
--skullet-text-bottomdescenderbaseline or descender — where it ends
<Skullet.skeleton id="profile" sample={@sample_user} theme={%{speed: "fast", radius: "8px"}}>
  …
</Skullet.skeleton>

Every row above is also a theme key — the name without the prefix, so theme={%{hold: "300ms", delay: "120ms", enter_filter: "blur(6px)"}} sets those three for this skeleton alone, and <Skullet.provider theme={…}> sets them for everything inside.

A theme becomes a <style> block for that element's id rather than a style attribute, so it survives a Content Security Policy: pass nonce={@csp_nonce} along with it — see usage.

Colours follow the page's color-scheme, so a light page on a dark desktop keeps light bars. Under prefers-reduced-motion bars hold still and every reveal is instant.

One place for the look

Everything inside a provider inherits its look, so you set it once:

<Skullet.provider mode="dark" animation="group-shimmer" speed="fast" theme={%{radius: "6px"}}>
  <.page />
</Skullet.provider>

theme, animation and speed become the custom properties the skeletons inside inherit; a skeleton's own theme still wins.

Mode

mode sets color-scheme on the wrapper, and that is the palette the bars are drawn from — not the page's. It is how one subtree asks for the other scheme: a dark panel on a light page wants dark bars, so it wraps them in <Skullet.provider mode="dark">. Leave it unset and the bars follow whatever color-scheme the page sets, which is what a theme toggle does.

Both palettes are low-alpha fills meant for their own background — light bars on a light page are rgb(128 128 128 / 0.2), dark ones are rgb(255 255 255 / 0.09). Forcing the wrong one onto a surface makes the bars nearly invisible, so match mode to what is behind the skeleton.

Animation

shimmer gives every bar its own band, all in one phase; group-shimmer sweeps a single band across the whole skeleton, which reads better when the bars are close together. Both follow the same rule as upstream: the band is capped at 320px, bands are 2.5 band-widths apart on a 110° slant, and the loop is timed to a 1280px reference width so the pace is the same on any screen. pulse fades the bars in and out, and none holds them still.