Animation Recipes

Scroll-driven reveals, pointer-tilt, and pinned sticky grids — all wired via data-sp-anim attributes. The HTML is identical to every other section above; only the attributes change. Disable JS or turn on Reduce Motion to confirm content stays visible.

Reveal on scroll

Fade in

This card starts transparent and 24px below its final position. When it enters the viewport, it animates into place once.

Staggered

The same recipe, delayed 150ms. Stack several of these in a row and you get a natural cascade without writing a timeline.

Last in line

Each card is an independent ScrollTrigger — the bootstrap registers one per element and disposes them on teardown.

Pointer tilt on hover

Subtle tilt

Move your cursor over this card — it tracks the pointer via gsap.quickTo. Coarse pointers (touch) and reduced-motion users skip it.

Stronger tilt

Same recipe, max: 14 degrees instead of the default 8. Options flow through the data-sp-anim-opts JSON blob.

Combined

Multiple recipes on one element — space-separated. This card reveals on scroll and tilts on hover.

Word-mask reveal

Words slide up from behind an invisible mask, one after another, as the block enters the viewport.

The recipe splits on whitespace, wraps each word in a clipping box, animates the inner span from below, then restores the original markup on dispose. Screen readers see the intact sentence via aria-label.

Scroll-mask reveal

A clip-path tween scrubbed to scroll progress. Put data-sp-anim="scrollMask" on any element (or a composition with a [data-sp-anim-role="mask-target"] child, like Feature) and it reveals as the block enters the viewport.

inset 40% → 0%

circle 10% → 80%

soft edge, later start

Parallax drift

Three decorative frames moving at different scroll rates across a full viewport. Positive speed means slower than the page; negative values move against it.

Stack pin & fade

Full-viewport panels stack and pin as you scroll. Tall panels fake-scroll their inner content before the panel itself scales down and fades out, revealing the next one. Ported from the GreenSock "Slides Pinning – Overscroll" CodePen as a single data-sp-anim="stackPinFade" recipe; the final panel is the landing destination and is not animated.

Panel one

Short content — fits the viewport, pins, scales down and fades.

Panel two — overscroll

This panel is taller than the viewport. While it is pinned, the recipe fake-scrolls the inner content upward, simulating an internal scroll without any nested scroll container.

The computed marginBottom on the panel extends the scroll budget by exactly the overshoot height, so the user's scroll distance maps 1:1 to the translate.

Only once the inner content has fully scrolled past does the scale-and-fade take over — at which point the panel unpins and reveals the next one below.

Everything is driven by a single scrubbed GSAP timeline per panel, shared across short and tall variants. The recipe reads [data-sp-anim-role="slide"] children of its wrapper and infers which branch to use per panel based on the inner height vs. viewport height.

Resize the window while scrolled in — the end offset and translate distance recompute automatically via invalidateOnRefresh.

Panel three

Another short panel — short panels skip the fake-scroll phase and go straight to scale + fade.

Panel four

The last animated panel — scales down to reveal the landing destination below.

Landing panel

Not animated — this is where the stack settles. Keep scrolling for the rest of the page.

Typography scroll effects

Per-character and per-word reveals scrubbed to scroll progress. Distilled from the Codrops OnScrollTypographyAnimations demo into a family of individual recipes — each one tree-shakeable, each addressable directly via data-sp-anim="...". Available: charTumble, charZoom, charFlipTop, charFlipBottomRandom, charFanOut, charScatter, charScaleSlide, charElasticDrop, charScaleYPinned, charScaleYAlternatingPinned, wordFlyoutPinned, charBlurArc, charScaleCorner, wordFadeTilt.

Characters tumble in from random angles as you scroll.

Each letter zooms forward from deep space.

Letters flip up in a randomized cascade.

Blurred arcs resolve into focus from the center out.

The section pins and characters rise from the baseline.

Scroll story

A pinned image column on one side, tall info blocks on the other. Each info block occupies a full viewport, so scrolling naturally steps through them while the pinned image stack collapses its top layer with a clip-path wipe — revealing the next image beneath. One data-sp-anim="scrollStory" on the wrapper plus [data-sp-anim-role="pinned"] on the image column and [data-sp-anim-role="frame"] on each image.

Chapter 01

Green Cityscape

Vibrant streets with vertical gardens and solar buildings. An oasis that thrives on renewable energy, smart transport, and green spaces for biodiversity.

Chapter 02

Blue Urban Oasis

Avenues with azure facades and eco-structures — clean energy, smart transit, and urban parks sheltering native wildlife.

Chapter 03

Fluid Architecture

Desert refuge with fluid architecture and glowing interiors — a sanctuary drawing on solar power, sustainable design, and natural harmony.

Chapter 04

Martian Arches

Ethereal structures arc over tranquil waters, bathed in the glow of a setting Martian sun — stark, desolate beauty on the red planet.

Green cityscape
Blue urban oasis
Fluid architecture
Martian arches

Elastic grid scroll

A grid that reacts to scroll velocity — tiles stretch and skew as you fling the page, then elastically snap back to rest the moment you stop. Each tile has a slightly longer return duration than the last, so they settle in a staggered wave. One data-sp-anim="elasticGrid" on the wrapper; every direct child becomes a tile.

Throw the mouse wheel at it — notice how the top row snaps back first and the bottom row lingers. Tune maxSkew, maxStretch, stagger, and ease via data-sp-anim-opts.

Gooey cursor field

A CSS Grid of tiles overlays each surface. Mousemove lights the tile under the pointer with a short TTL fade; adjacent lit tiles merge through an SVG feGaussianBlur + feColorMatrix gooey filter. Click for a radial stagger ripple from the click point. Colors, blend mode, and tile shape are driven by inline --sp-cursor-* custom properties — one data-sp-anim="cursorField" drives every variant. Scroll through the full-viewport showcases below.

Move your mouse across this surface

Square tiles, exclusion blend, 24 columns — the default recipe.

Dense circle tiles

32 columns, longer TTL, round tiles — the blobs merge like lava.

Click anywhere inside

Radial-gradient tile fill — click fires a glow-out ripple staggered across the grid from the click point.

Scroll-driven, zero-chore.

Twelve tiles converge, the grid zooms into place, the title locks center and the call to action fades in — all from one data-sp-anim attribute on a single wrapper.

Vertical scroll → horizontal track

Keep scrolling down — the page captures the scroll, pins this section, and translates the track sideways through five panels. Release happens at the end, footer follows cleanly.

One

Two

Three

Four

Five

Welcome to www.uygulama.org

This is a sample page rendered by SeoPages. Every component on this page comes from the @seopages/ui library — pure CSS, zero JavaScript, fully accessible HTML.

Features

Fast Rendering

Server-side rendered HTML delivered from the edge. No client-side JavaScript required.

SEO Optimized

Semantic HTML with proper heading hierarchy, accessible landmarks, and crawlable content.

Fully Themeable

Override CSS custom properties to match any brand. No rebuild needed — just set your tokens.

Content Layout

Main Content

The display uses auto-fill with a minimum column width. Items flow naturally and wrap responsively — no breakpoints needed.

The card uses the outlined variant with large padding, making it suitable for primary content areas.

Sidebar

Cards sit side by side when there's room, and stack when there isn't.

Card Variants

Outlined

Default card with a subtle border. Clean and minimal.

Elevated

Surface-filled card. Draws attention to featured content.

Flat

No border, transparent. Blends into the background.

Masonry Layout

Short Card

Just a quick note.

Tall Card

This card has more content to demonstrate how masonry fills vertical gaps. Items pack tightly instead of aligning to rigid row heights.

The layout adapts naturally to varying content lengths — perfect for galleries, testimonials, or blog post grids.

Medium Card

Somewhere in between. The masonry layout places this card optimally to minimize whitespace.

Another Short One

Compact and tidy.

Extra Tall Card

This card is the tallest of the bunch. In a standard grid, all items in the same row would stretch to match this height, leaving awkward gaps.

With masonry, each item takes only the vertical space it needs. The next item slots into the shortest column automatically.

No JavaScript required — pure CSS via display: grid-lanes.

Final Card

Wraps up the masonry demo. Resize the browser to see columns reflow.

Border Component

Gradient Border

A vibrant gradient wraps this card. The "border" is actually padding on a wrapper div with a CSS background.

Thick Gradient

Larger width and radius make the gradient border more prominent. Works with any CSS background value.

Conic Gradient

A rainbow conic gradient border — impossible with native CSS borders.

Pattern Border

Repeating stripes as a border — any CSS background pattern works here.

Video Border

A looping video plays behind the padding area, creating an animated border effect. The inner content sits above the video via z-index.

Carousel Component

Horizontal scroll-snap with native CSS pagination dots via ::scroll-marker — zero JavaScript.

Mask Component

Vertical Clip

The mask clips content to its bounds — no fade, just a hard edge.

Scroll this block to see how overflow is clipped naturally.

No JavaScript, no overlays — pure CSS overflow on a wrapper div.

Useful for scrollable lists or constraining overflowing children.

Works in every browser — just overflow: hidden.

Pairs with any primitive that might overflow its container.

Horizontal Clip

Frame Clip

Stack Component

SwiftUI-style HStack / VStack / ZStack via the direction prop. Pure flexbox for horizontal/vertical, single-cell grid for depth.

Horizontal (HStack)

Vertical (VStack)

Button Group

Merged buttons with zero gap — only the first and last keep their outer corners.

Justify: space-between

Left

Middle

Atomic Utilities

Minimal, sp-* prefixed atomic classes — spacing scale 0–5 driven by --sp-space, flex/grid centering, z-index, text align, and size. Apply via className on any primitive.

Centering — sp-center

Horizontally + vertically centered

One class on the wrapper does the whole job.

Grid centering — sp-place-center

place-items: center

Spacing scale — sp-p-{0–5}, sp-m-{0–5}

sp-p-1

sp-p-2

sp-p-3

sp-p-4

sp-p-5

Directional — sp-mt-4, sp-pb-2, sp-mx-auto

Baseline text.

Heading with sp-mt-4 sp-pb-2

Follows with consistent rhythm.

Z-index — sp-z-{0,10,20,30}

z-0

z-10

z-20

Text align — sp-text-{left,center,right}

sp-text-left

sp-text-center

sp-text-right

Flex row with gap — sp-flex sp-gap-3

Leading

Code Component

Inline variant flows with prose. Block variant renders a scrollable <pre><code> surface with an optional language label. Uses --sp-font-mono and global radius, border, and space tokens.

import { Modal, Button } from "@seopages/ui";

export function ConfirmDelete() {
  return (
    <Modal id="confirm" size="sm">
      <Title as="h3">Delete this item?</Title>
      <Text>This cannot be undone.</Text>
      <ButtonGroup>
        <Button href="#!" variant="outline">Cancel</Button>
        <Button href="#!">Delete</Button>
      </ButtonGroup>
    </Modal>
  );
}
.sp-card {
  background-color: var(--sp-color-surface);
  border-radius: var(--sp-radius);
  padding: var(--sp-space);
  font-family: var(--sp-font-body);
}
make render-dev    # local Astro dev with .env.development
make render-deploy # build + push secrets + wrangler deploy
A plain block without a language label, with wrap enabled — long lines break instead of scrolling horizontally. Useful for prose-adjacent snippets where horizontal overflow would be disruptive to the reading flow.

Modal Component

Zero-JS <dialog> driven by :target. Open via a link to the modal's id, close via any link to a non-matching hash (default #!). Click the backdrop or the ✕ to dismiss.

Small modal

Compact width — good for brief prompts, toasts, or single-field forms.

Medium modal

Default width. The dialog surface uses --sp-color-surface, --sp-radius, and --sp-space — flipping dark mode above recolors this modal automatically.

Try pressing the dark-mode toggle in the header with this modal open — no re-render needed, tokens cascade through.

Large modal

Wider surface suitable for forms, media previews, or multi-column content.

Column one

Modal content composes with every other primitive — Card, Grid, Text, Title, Button.

Column two

Scrolls internally when content exceeds 90vh.

Delete this item?

This action cannot be undone.

Collapse Component

Native <details> / <summary> — zero JavaScript, keyboard accessible, theme tokens cascade (try the dark-mode toggle).

What is SeoPages?

SeoPages renders tenant websites from a shared component library at the edge. Every page is static HTML, cached aggressively, and invalidated on demand.

This disclosure block is a single Collapse primitive wrapping plain text — click the summary to collapse it.

FAQ composition

Frequently asked

Do I need JavaScript to use this?

No. The Collapse primitive uses the native <details> element. Sharing a `name` across siblings makes opening one close the others — the HTML spec handles it.

How does theming work?

Every surface, spacing, and radius value pulls from --sp-* custom properties. Flip the dark-mode toggle in the header with a trigger open — the colors update without remounting.

Is it accessible?

The summary is keyboard-focusable; Space and Enter toggle it. Screen readers announce expanded/collapsed state via the native element, and a visible focus ring uses --sp-color-primary.

Flat variant, composed content

Show nested layout

Composes freely

Collapse holds any primitive — Cards, Grids, Stacks, even another Collapse.

Flat inside a surface

The flat variant drops its border so the parent Card owns the outline.

Dropdown Component

Native <details> disclosure with compound subcomponents — Dropdown.Item, Dropdown.Action, Dropdown.Divider, Dropdown.Header. Honest disclosure semantics (no fake role="menu"), zero JavaScript. Sharing name across siblings makes opening one close the others.

Resources
Products
Account
Settings Billing

Feature composition

A two-column block built from the Image, Title, Text, and Button primitives. Swap imagePosition between "left" and "right"; columns collapse to a single stack below the mobile breakpoint.

Abstract editorial photograph
Image left

Ship pages without writing JavaScript

Every primitive in the library is a pure function from props to HTML. Compose them into sections, drop them in an Astro page, and let the edge cache do the rest.

Soft gradient texture
Image right

Themeable down to the last pixel

Override any --sp-* token on a wrapper element and the whole composition retunes — no rebuild, no remount, no surprises in dark mode.

Wide editorial photograph
Centered

One block, perfectly centered

Use imagePosition="top" or "bottom" for hero-style layouts. Content stacks above or below the image and aligns to the center.

Gallery tile oneGallery tile two
Multiple images

Pass an array, get a gallery

The image prop accepts a single object or an array. Two images render as a 1×2 grid, three as a 1×3, four as a 2×2 — the layout adapts to the count.

Mood board tile oneMood board tile twoMood board tile three
Centered + multi

Centered headline above a triptych

Image grid sits below the centered content block, capped at the same stacked max width as the single-image variant.

Editorial landscape revealed through a scroll-driven mask
Scroll-mask reveal

Unveil media as you scroll past it

Drop data-sp-anim="scrollMask" on the Feature root and its image reveals through an expanding clip-path scrubbed to scroll progress. Tune shape, from/to, radius, and start/end via data-sp-anim-opts — no component changes, no extra markup.

Portrait revealed through a scroll-driven circular mask
Circular variant

Or reveal through a growing circle

Same recipe, shape:"circle" — the image opens from a small centered disc outward to cover the frame. Swap from / to percentages to tune how early the reveal starts and how much overshoot you want at the corners.

Footer composition