The library

Techniques, not templates

Every trick recreated from the source video as a live, self-contained demo. Search, filter, open, steal.

01 / 96

Neon Sign: The Letters Are White

The letters are white. Every bit of color is in the shadow behind them, which is why this reads as glass and gas rather than as colored text. Four shadows do it, at 4, 12, 28 and 60 pixels: the first is white and tight so the glyph keeps a hot core, and the other three are the hue, each wider than the last. Stacking them is what makes the falloff, since a single large blur only ever gives a flat halo. The border is the same tube bent into a rectangle, the shadow stack repeated as box-shadow outward and inward so it lights both the wall behind it and the air it encloses. One custom property carries the color, so a swatch sets --neon and nothing else.

animationcssglowtext-effecttext-shadow
02 / 96

Gliding Pill Nav, No Measuring

A pill that follows the pointer without measuring anything. The hovered link takes anchor-name: --pill, and the rail's ::before sets position-anchor: --pill and inset: anchor(top) anchor(right) anchor(bottom) anchor(left), so its four edges are that link's four edges: it becomes the link, wherever the link sits. Transitioning inset turns the jump into a glide. Two elements holding one anchor name is not an error, it is worse: the later one in the DOM quietly wins, so an active link at the end of the rail steals the pill back from anything hovered before it. While the rail has a hovered link, the resting link gives up the name. The rail carries no padding, no gap and square links, because hit testing follows border-radius and any dead pixel hands the pill back mid-glide.

animationcsslayouthoveranchor-positioningnavigation
03 / 96

Odometer Price Roll

No digit is ever rewritten. Each column is a strip of 0 to 9 behind a window one line tall, and translate: 0 calc(var(--d) * -1lh) slides the strip until digit --d is the one showing. 1lh is the whole trick: the window and the step are both read off the same line box, so the strip stays in register at any font size without one pixel value anywhere. Changing the price is then changing two numbers, and :has lets the checkbox do it from inside the card, so .card:has(#yearly:checked) rewrites --tens and --ones and the wheels follow. A spring ease overshoots by a hair so each wheel settles instead of stopping dead, and the ones column starts a beat after the tens so the count cascades.

animationcssvariablestransition:hasodometer
04 / 96

3D Carousel: Rotate, Then Push

One rule places every card. rotateY() turns the card to its seat, which re-aims the card's own z axis outwards, and translateZ() then walks it along that new axis to the rim, so only --i changes. Swap the two and every card is pushed at the camera before it turns: the rotation swings one stack around the parent and you get a fan, not a ring. The radius is derived, not guessed. The cards are the sides of a regular polygon, each side one card plus one gap long, so r = (card + gap) / 2tan(180deg / n): pick the gap and the radius follows, which is why the count buttons set --n and nothing else. The spin is one keyframe on a registered --angle, so a drag can take the wheel and hand it straight back.

animationcssuicarouseljavascript3dinteractiontransformperspective
05 / 96

Seamless Marquee: Two Copies, Half a Slide

A marquee loops with no visible jump when the run is repeated twice and slid by exactly half the track: half the track is one whole copy, so at the end copy two stands where copy one started and the restart has nothing to show. Three details decide it. The travel has to be translateX(-50%), a percentage of the element being transformed, so it tracks the run's width on its own. The track needs width: max-content, or it wraps at the parent's width. And the spacing belongs to the items, not the track: a gap sits between the two copies as well as inside them, so a 34px track gap puts one copy 17px out of step, while padding-inline-end leaves the halves identical.

animationcssno-jsmarqueetransformkeyframesticker
06 / 96

Pulsing Status Dot: The Ring Is a Box Shadow

A pulsing status dot is usually three elements: a wrapper, a ring, and the dot. It needs one. box-shadow paints outside the border box and takes no part in layout, so the halo is a second shape the element already owns: grow the spread from 0 to 14px while the alpha runs out and the ring swells past the dot, moving nothing around it. One span, two keyframes. The shadow reads color-mix(in srgb, var(--dot) 70%, transparent), so green, red, amber and blue all run the same pulse, and it inherits border-radius, so the circle and the rounded square differ by that one property. cubic-bezier(0, 0, .35, 1) throws the spread out at once and then crawls, which is what a ripple looks like; linear reads as a blinking outline.

animationcssbox-shadowno-jskeyframesstatuspulse
07 / 96

Scroll-Driven Animation: The Scroll Is the Clock

A scroll-driven animation is an ordinary @keyframes animation with its clock swapped out: animation-timeline: view() replaces time with the element's own trip through its scroller. Nothing fires, nothing needs teardown, and it runs on the compositor. animation-range picks which slice of that trip the keyframes get: cover, entry, exit, contain. Rings and cards pin with position: sticky and read scroll(), since view() times an element against travel a pinned box no longer has. Rows stagger inside entry, because animation-delay is a length of time and this timeline has none. Two traps: animation-timeline goes after the animation shorthand, which resets it, and @supports has to land everything finished where scroll timelines are missing.

animationcssscrollno-jsanimation-timelinescroll-drivenanimation-range
08 / 96

Skeleton Shimmer: Paint Wider Than the Box

A shimmer is one gradient painted wider than the element that shows it, then slid sideways: the box never moves, only the paint inside it. The first tab is the everyday skeleton at the reel's 1.2s. The second is the mechanism, slowed to 6s with the clipped overhang drawn faintly beside the box. Three things decide whether it loops cleanly. The travel has to equal the image width, not the element width, or the gradient jumps at the wrap. The stops sit at 25/50/75 rather than 0/50/100, so the image starts and ends on the same color and repeat-x shows no seam. And the offset is in pixels, because a background-position percentage resolves against (box - image), negative once the image is the wider of the two.

animationcssgradientloadingskeletonbackground-position
09 / 96

Sprite Sheet Animation with steps()

A sprite sheet is one image and a keyframe that slides it: background-position travels the sheet's full width while steps(10) freezes it on each frame for 140ms, so the browser draws ten discrete poses instead of tweening between them. The strip above is the same image at 3x, running the same duration and step count, so it always sits over the frame being drawn below. Three things decide whether it lines up. The travel is the whole sheet width, not one frame short: steps() defaults to jump-end and never lands on the end value. background-size is in pixels, because a percentage there resolves against the element and the frames would drift. And image-rendering: pixelated, or 18px art smooths into mush.

animationcsskeyframespixel-artspritegame-ui
10 / 96

Staggered Reveals with sibling-index()

Five staggers, one function, and no :nth-child ladder anywhere: sibling-index() reads each element's own position in its parent, so rows added or reordered later re-stagger themselves. The list is the reel's code verbatim, animation-delay: calc(sibling-index() * 100ms). The equalizer drives three properties from one call: delay, height through sin(), and hue. Orbit uses the index as geometry rather than timing, rotate(calc(sibling-index() * 30deg)) translateY(-56px) for twelve dots with no coordinates. Grid turns the flat index into coordinates with mod() and round(down), whose sum sweeps a diagonal ripple. Each declaration sits after a plain fallback. Chrome 149+ and Safari 26.5.

animationcssstaggeredlistcustom-propertiesnth-child
11 / 96

Animated Gradient Text Glow

One gradient, clipped to the glyphs and animated by background-position, fills the text; a pseudo-element repeats the same clipped gradient behind it and blurs it into a halo that travels with the color. Two details make or break it. The glow copy must be set in the same font as the heading — leave the size on the wrapper and an h1 takes its 2em default, so the halo renders at half scale and reads as a smudge beside the word rather than light coming off it. And the wrapper needs isolation: isolate, because z-index: -1 without a stacking context of its own drops the glow behind the page background instead of behind the text. The gradient repeats its first color last, so the loop has no seam.

animationcssgradientglowtext effectbackground-clip
12 / 96

Rotating Glow Border with @property

A conic gradient can start at any angle, and until that angle is a registered custom property the browser refuses to interpolate it — so the border jumps instead of sweeping. Declare it with @property and one spinning gradient serves a card, an avatar ring and a button, each changing only its palette, speed and direction. The halo is the same gradient again, blurred behind the edge. Worth knowing: inherits is a required descriptor, not an optional one. Leave it out and the whole rule is invalid, --a never registers, and every gradient silently computes to none.

animationcssui/uxgradientconic-gradient@property