Products

Prompts to copy, pieces to ship

Every prompt recreates a real piece of this website — exact colors, sizes, timings and behavior included.

17Prompts

Live preview

Landing Pages

Monochrome Studio Landing

A calm, bold home page: pill navbar, compact hero, a dark featured grid that grows on scroll, a lime email CTA and a bento footer.

Prompt

Build a minimal, monochrome studio landing page. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. LAYOUT, top to bottom: 1. NAVBAR - No background. Padding 30px top, left and right (20px on phones). - Left: text logo "Your Studio" with a superscript ™ at 0.6em, semibold, 20px (18px on phones). - Center (absolutely centered, hidden below 768px): links Products, About, Contact — 14px medium, 32px apart. Each opens a hover dropdown card (see "Pill Navbar with Hover Dropdowns"). Products also lists a disabled "Agent Skills" pill (see "Coming Soon Roll Pill"). - Right: a 28px account icon — a solid #1e1e1e circle with the head and shoulders cut out (transparent). Hover opens a right-aligned dropdown with "Create Account" (black pill) and "Sign In" (light pill). - Below 768px, replace the center links and account icon with a 40px black round menu button that opens a full-screen menu. 2. HERO - Flex column, centered, 20px gap, padding 32px top/bottom plus the side gutter. - Min-height: max(320px, calc(40svh - 70px)) from 1024px. max(260px, calc(30svh - 70px)) from 768px. max(260px, calc(30svh - 60px)) on phones. - Announcement pill: a link to /products. 32px tall, padding 0 14px, background #f6f6f8, 12px medium (14px from 768px), with an 8px lime #a3f207 dot, the text "{product count} new prompts, now with video previews", and a 12px diagonal arrow. - One centered h1 on two lines: "Prompts to Copy," / "to Build Your Website", at clamp(1.75rem, 4.2vw, 3.75rem), semibold, leading 0.95, tracking -0.04em. - Under it, the tech-stack marquee (see "Tech Stack Marquee"). 3. FEATURED SECTION (dark, grows on scroll — see "Scroll-Grow Section") - Dark tokens inside: background #111112, cards #1c1c1e, borders #2e2e32, text #f2f2f4, muted #8a8a8f. - Starts 80px below the hero (32px on phones), inset 80px from the sides (32px), with 64px corners (40px). Inner padding 16px (12px on phones). - Header row: 12px uppercase "Featured" label, h2 "Featured prompts" at clamp(2rem, 5vw, 4rem), semibold, and a short muted line. From 768px, a white "View all products ↗" pill (56px tall) sits on the right. - A grid of 9 product cards (see "Prompt Product Card"): 3 columns from 1024px, 2 from 768px, 1 on phones, 16px gap (12px on phones). - Below the grid: a full-width white "View all {count} products ↗" pill, 56px tall. 4. EMAIL CTA (see "Lime Email CTA Card") - A lime card right after the featured section: one small line with an inline "contact form" pill, then a big email address with Copy and Send buttons. 5. FOOTER - Bento grid of 4 cards (see "Bento Footer"), then a small row with "© {year} Your Studio™" on the left and a "Legals" link on the right. GLOBAL DETAILS - Text selection: background #a3f207, text #1e1e1e. - Scrollbar: 12px wide, transparent track, #1e1e1e pill thumb with a 3px border in the page color. - Fully responsive. No hover color changes anywhere.

Next.jsTailwindGSAP
Live preview

UI Components

Pill Navbar with Hover Dropdowns

Transparent navbar with centered links that fade in rounded dropdown cards of pill buttons.

Prompt

Build a transparent navbar with hover dropdowns made of pill buttons. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. STRUCTURE - Header: flex, items centered, space-between. Padding 30px top/left/right (20px below 768px). position: relative, z-index 40. - Left: text logo with a superscript ™ (0.6em, margin-left 2px), 20px semibold. - Center nav: position absolute, left 50%, translateX(-50%). Links 14px medium, 32px gap. Hidden below 768px. - Right: account icon button, 40×40 hit area with a 28px icon. DROPDOWNS (CSS only — group-hover + group-focus-within) - Each nav item is a relative "group". Its panel is absolute at top: 100% with 12px top padding, so the pointer can cross the gap without closing it. - Center-nav panels are centered under their link. The account panel is right-aligned to the icon with 8px top padding. - Hidden state: opacity 0, visibility hidden, pointer-events none. Open state: opacity 1, visible, pointer-events auto. Transition all 200ms. - Card: 208px wide (192px for the account card), background #f6f6f8, 1px border #dcdde2, radius 28px, padding 8px, gap 6px, shadow-lg. - Pills: height 40px, fully rounded, text centered, 14px medium. The first or main pill is black (#1e1e1e, white text). The rest use #edeef2. MENU CONTENT - Products: View all (black), Landing Pages, UI Components, Web Templates, Animations, then a disabled "Agent Skills" pill that rolls to "Coming soon" on hover (see "Coming Soon Roll Pill"). - About: Studio (black), Your-site.com, Legals. - Contact: Form (black), then one row of three equal round pills with Instagram, LinkedIn and X icons. They open in a new tab and each has an aria-label. - Account: Create Account (black), Sign In. CLOSE AFTER NAVIGATION - After a route change, blur the focused element and add a data-suppress attribute on the header. That attribute forces every panel hidden. - Remove it on the first pointerover outside the nav groups, so a clicked dropdown doesn't stay open on the new page. No hover color changes on any link or pill.

NavbarDropdownCSS only
Live preview

UI Components

Bento Footer

Four-card bento footer: a big black call-to-action, a gray link card, and purple and lime cards.

Prompt

Build a bento-grid footer. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. CONTAINER - Footer padding 30px on all sides (20px on phones). - Grid gap 16px (12px on phones). - From 768px: 2 columns, rows minmax(260px, 1fr) twice. Below 768px: everything stacks. CARD 1 — left, spans both rows, background #1e1e1e, white text - Padding 40px (24px on phones), min-height 420px (380px on phones). - Content spread between top and bottom (flex column, justify-between). - Top: 12px medium uppercase label "Your Studio™ library". Then an h2 "Copy a prompt." / "Ship your website." at clamp(2.25rem, 4.5vw, 4rem), medium weight, leading 1.05, tracking -0.03em, 24px above, max-width 28rem. - Bottom: a split button with 16px radius, background #f6f6f8, dark text. - Left part: padding 24px × 12px, two lines — "Browse" (10px uppercase, #8a8a8f) and "All prompts" (16px semibold). - Right part: a 22px cart icon (1.5px stroke) with 24px side padding and a 1px #dcdde2 left border running the full height. - A working prompt card, 1024px and up only: 256px wide, bottom/right 40px, rotated -4deg, white at 10% opacity, radius 22px, padding 16px. - Top row: a 10px uppercase label "PROMPT · {prompt title}" at 60% white, and a small white "COPY" pill (10px semibold uppercase, padding 4px 12px, 11px copy icon). - The pill copies a real full prompt to the clipboard and shows a check with "COPIED!" for 2 seconds. If the clipboard fails, fall back to window.prompt. - Below: that prompt's text in 11px monospace at 80% white, clamped to 3 lines. CARD 2 — top right, background #d9d9dc - Padding 24px, min-height 260px (200px on phones). - Top row: 12px uppercase label "World of Your Studio", and a 22px diagonal arrow (path "M6 18 18 6M8 6h10v10", 1.5px stroke). - Bottom: "Visit yoursite.com" at clamp(1.75rem, 3vw, 2.5rem), medium, leading 1, tracking -0.03em. CARDS 3 & 4 — bottom right, a 2-column grid with the same gap, min-height 260px (200px on phones), padding 24px (20px on phones) - Purple #c084fc card, white text: label "Discover" / "our story" with the diagonal arrow, title "About us". - Lime #a3f207 card, dark text: label "Have some" / "questions?" with a paper-plane icon, title "Contact us". - Titles: clamp(1.5rem, 2.6vw, 2.5rem), medium, leading 1, tracking -0.03em. BOTTOM ROW - 24px below the grid. 12px #8a8a8f text, space-between. - "© {current year} Your Studio™" on the left and a "Legals" link on the right. Every card is a link. No hover color changes.

FooterBento gridResponsive
Live preview

UI Components

Full-Screen Mobile Menu

A smooth, full-screen phone menu with big rounded link rows, account pills and socials.

Prompt

Build a full-screen mobile menu, shown only below 768px. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. TOGGLE BUTTON - 40px round, background #1e1e1e, white icon. position relative, z-index 70, so it stays above the overlay. Add touch-action: manipulation. - Icon: two 2px bars, 18px wide and 10px apart, inside a 12px-tall box. - Open: both bars move to the middle and rotate +45° and -45° to form an ✕. Animate transform only, 300ms. - aria-label switches between "Open menu" and "Close menu". Add aria-expanded and aria-controls. OVERLAY - position fixed, inset 0, z-index 60, background #edeef2, padding 20px (24px at the bottom). Flex column, overflow-y auto, overscroll-behavior contain. - Fade with opacity only, 300ms. When closed: pointer-events none and the inert attribute. - While open: set overflow: hidden on <html>. Close on Escape, on any link click, and when the viewport reaches 768px. CONTENT - Top: the text logo with superscript ™, in a 40px-tall row aligned with the toggle. - 32px below: three link rows — Products, About, Contact. Each row: - 64px tall, radius 28px, background #f6f6f8, padding 0 24px. - Text 30px semibold, tracking -0.03em, with a 22px diagonal arrow on the right. 8px gap between rows. - Then wrapped chips: Landing Pages, UI Components, Web Templates, Animations — 36px tall, 1px #dcdde2 border, 14px medium. Last comes a disabled "Agent Skills" chip with a dashed border and a small lime "SOON" tag (see "Coming Soon Roll Pill"). - Pushed to the bottom (margin-top auto): - A 2-column row: "Create Account" (black pill) and "Sign In" (#f6f6f8 pill), both 56px tall. - A row of three equal 56px pills with Instagram, LinkedIn and X icons. - 12px #8a8a8f text: "© {year} Your Studio™" on the left, "Your-site.com" and "Legals" on the right. STAGGERED ENTRANCE - Each block animates opacity 0→1 and translateY 12px→0, 300ms ease-out. - When opening, block i gets transition-delay 80ms + i×40ms. When closing, delay is 0 so everything leaves together. - Only animate opacity and transform, so it never lags.

MobileMenuAccessible
Live preview

UI Components

Contact Form with Topic Pills

Rounded contact form with selectable topic pills, inline validation and a success state.

Prompt

Build a contact form with topic pills and server-side validation. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Use a Server Action with React useActionState. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. CARD - <form> with background #f6f6f8, radius 28px, padding 12px (16px from 768px). Flex column, 12px gap. - It should stretch to the height of its grid row. TOPIC PILLS - A fieldset with legend "I'm interested in" (12px uppercase, #8a8a8f, 12px below). - Radio options, styled as pills: Products, Custom prompt, Custom website/app, Collaboration, Other. - Each is a visually hidden radio plus a span: 44px tall on phones (40px from 768px), padding 0 16px, 1px #dcdde2 border, 14px medium. - Checked: background and border #1e1e1e, white text. Focus-visible: a 2px #1e1e1e ring. The first option is checked by default. FIELDS - Name and Email sit side by side from 768px. - Both: 56px tall, fully rounded, background #edeef2, padding 0 20px (24px from 768px), 16px text, #8a8a8f placeholder. - No outline; a 2px #1e1e1e ring on focus. Use autocomplete name/email and add aria-labels. - Message: textarea, 5 rows, min-height 160px, radius 24px, same styling, resize none. - Put it in a flex-1 wrapper so it grows and keeps the submit button at the bottom of the card. SUBMIT - Full-width 56px black pill: "Send message" with a paper-plane icon. - Shows "Sending…" and 60% opacity while pending. VALIDATION (on the server) - Name required. Email must match a basic email pattern. Message at least 10 characters. - Return { ok, errors } and show each error under its field: 12px, red, padding 0 24px. SUCCESS STATE - Replace the form with a #f6f6f8 card (radius 28px, min-height 360px; 420px from 768px), centered. - Inside: a 56px lime #a3f207 circle with a check icon, "Message received" (30px semibold), and a muted thank-you line.

FormServer ActionValidation
Live preview

Web Templates

Contact Page Template

Two-column contact page: dark intro card with socials, the topic-pill form, and a full-width email card.

Prompt

Build a complete contact page. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. PAGE GRID - Padding: side gutter, 24px top on phones and 64px from 768px. Gap 12px (16px from 768px). - 2 columns from 1024px; stacked below. 1. INTRO CARD (left) - Background #1e1e1e, white text, radius 28px, padding 24px (40px from 768px). Flex column, justify-between, 32px gap. - Top: - 12px uppercase label "Have some questions?". - h1 "Let's build" / "something together" at clamp(2.25rem, 5vw, 4rem), semibold, leading 1.02, tracking -0.04em. - A short line of white text at 60% opacity: 16px, 18px from 768px, max-width 24rem. - Bottom: "Follow us" label, then 48px round Instagram, LinkedIn and X icon buttons with a 10% white background. 2. FORM CARD (right) - The "Contact Form with Topic Pills" form, stretched to the same height as the intro card. The message box grows so "Send message" lines up with the bottom of the intro card. 3. EMAIL CARD (full width, spans both columns) - Background #d9d9dc, radius 28px, centered content. - Padding 48px × 20px on phones, 80px × 24px from 768px. - 12px uppercase label "Or drop us an email at". - The email address as a mailto link at clamp(1.5rem, 6vw, 5.5rem), semibold, leading 1, tracking -0.04em. Put a <wbr> after the "@" so it wraps cleanly on phones. - Two pills: - "Copy email": #f6f6f8, copy icon. Uses navigator.clipboard and shows a check icon with "Copied!" for 2 seconds. If the clipboard fails, fall back to window.prompt. - "Send email": black, diagonal arrow, mailto. - On phones they stack full-width at 56px tall. From 640px they sit side by side at 48px, min-width 160px. No hover color changes.

ContactCopy to clipboardResponsive
Live preview

Web Templates

Legal Pages with Sticky Navigator

Legal hub plus document pages with big readable text and a sticky topic navigator that tracks your scroll.

Prompt

Build a legal section: a hub page and statically generated document pages. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. DATA - One typed file with an array of documents: Terms of Service, Privacy Policy, License Agreement, Refund Policy, Cookie Policy. - Each document has { slug, title, summary, sections: { id, heading, body } }. - body is an array where a string is a paragraph and a string[] is a bullet list. - Also export one "last updated" date and a contact email. HUB (/legals) - Black header card (radius 28px, padding 24px; 40px from 768px): uppercase label "Legals", h1 "The fine print," / "kept simple" at clamp(2rem, 5vw, 4rem), and "Last updated …" at 60% white. - A grid of document cards: 1 column, 2 from 768px, 3 from 1024px. Each card: - #f6f6f8, radius 28px, padding 20px (32px from 768px), min-height 180px (220px from 768px). - The muted summary and a diagonal arrow on top; the title at the bottom (24px, 30px from 768px, semibold). DOCUMENT PAGE (/legals/[slug]) - Use generateStaticParams and dynamicParams = false. - Grid: 320px sidebar and content from 1024px. - Content: a black header card with a "← Legals" link, the title and the updated date. Then one #f6f6f8 card (padding 20px; 40px from 768px) with the sections. - Section headings: clamp(1.375rem, 2.6vw, 2.25rem), semibold. Sections are 36px apart (56px from 768px). - Body text: 16px on phones, 18px from 768px, 20px from 1024px, leading relaxed. - Bullets: 6px dots (8px from 768px) in #1e1e1e. - Give each section scroll-margin-top so anchored headings aren't hidden under sticky bars. STICKY TOPIC NAVIGATOR (client component) - Desktop (1024px and up): a sticky card at top 30px, max-height 100svh - 60px, scrollable. #f6f6f8, radius 28px, padding 12px. - "On this page": a list of section pills, min 48px tall, 18px medium. - Below a divider, "Legals": links to every document, with the current one highlighted on a #edeef2 pill. - Phones and tablets: a sticky bar at top 0 with the page background. - It's a single row of section pills that scrolls sideways with no visible scrollbar. - Pills are 40px tall and 14px (44px and 16px from 768px), with a 1px border. - It scrolls the active pill into view automatically. - Active section: the last section whose top is within 30% of the viewport height, and the last section at the bottom of the page. The active pill is black with white text, with a 200ms color transition. - Clicking a pill: preventDefault, scrollIntoView({ behavior: "smooth" }) and history.replaceState with the hash.

LegalSticky navStatic params
Live preview

Animations

Letter Roll Hover Text

GSAP split-text hover: each letter rolls up and is replaced by its twin, letter by letter, and always finishes.

Prompt

Build a reusable link component with a letter-by-letter "roll" hover effect using GSAP. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Install gsap. COMPONENT: RollLink({ href, className, children: string }) — a client component wrapping next/link. MARKUP - Put aria-label={children} on the link. Inside, an aria-hidden flex span. - Split children into characters, turning spaces into non-breaking spaces. For each character: - Outer span: relative, inline-block, overflow hidden, line-height 1.2. - Inner span with data-char, display block, containing the character. - A second copy of the character, absolutely positioned at top: 100%, left 0, directly underneath. ANIMATION (onMouseEnter only) - gsap.to(all [data-char] in this link, { yPercent: -100, duration: 0.22, ease: "power2.inOut", stagger: 0.015 }). - Each letter slides up out of view while its twin slides into its place, left to right. - onComplete: gsap.set(chars, { yPercent: 0 }) to reset instantly, which looks identical. RULES - Keep a "playing" ref. Ignore new mouseenter events while playing, and don't reverse on mouseleave, so the roll always finishes even if the pointer leaves early. - No color, background or opacity change on hover — the motion is the only feedback. - The link's own className controls layout, so it works for plain nav text and for centered pill buttons (e.g. flex, 40px tall, fully rounded, centered).

GSAPHoverSplit text
Live preview

Animations

Custom Cursor with Text Ring

Rounded Figma-style arrow plus a lagging ring of rotating text, blended with difference mode.

Prompt

Build a custom cursor: a rounded Figma-style arrow plus a ring of rotating text that follows with a lag. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Use gsap. SETUP - A client component mounted once in the root layout. Only run when matchMedia("(pointer: fine)") matches. - Global CSS: - Inside @media (pointer: fine), set cursor: none !important on *, *::before and *::after. - Inside @media (pointer: coarse), hide the component. - Wrapper: aria-hidden, pointer-events none, position fixed, inset 0, z-index 9999, mix-blend-mode: difference. Everything inside is pure white (#fff), so it inverts whatever is underneath. - IMPORTANT: give <html> its own background color (the same as body). Otherwise the body background moves to the canvas, the difference blend has nothing to blend with, and the cursor shows plain white. ARROW - A 28×28 SVG with path "M6 5v17.5l5.2-5.2h7.8Z", drawn twice for rounded corners: - First with a 4px stroke, round line joins and paint-order stroke. - Then with a 1.2px stroke and round joins. - Translate it by (-6px, -5px) so the tip sits exactly on the pointer. - Follows the pointer with gsap.quickTo on x/y, duration 0.05. RING - A 124×124 SVG with a thin circle (r 38, 0.75px stroke). - Text on a circular path of r 48: "WELCOME • SCROLL DOWN •". - 8.5px, uppercase, letter-spacing 0.5. - Use textLength 301 (≈ 2π×48) with lengthAdjust="spacing" so the text fills the circle evenly. - Spins with a CSS keyframe rotate(360deg), 10s linear infinite. - Centered with xPercent/yPercent -50. Follows with gsap.quickTo, duration 0.45, ease "power3.out", offset (+4px, +8px) so it centers on the arrow's body. BEHAVIOR - On the first pointermove, fade both to opacity 1 (0.2s). On pointerleave of the document, fade both out. - When the pointer is over any a or button (check with closest), shrink the ring's inner wrapper to scale 0.5 and opacity 0 (0.25s, power2.out). - When it leaves, bring the ring back after a 0.5s delay. Use overwrite: true so hovering another link cancels a pending reveal.

GSAPCursormix-blend-mode
Live preview

Animations

Shine Sweep Text

A glowing yellow band of light that sweeps left to right through the letters — not a static glow.

Prompt

Create a pure-CSS "shine sweep" text effect. A glowing yellow band of light travels left to right through the letters on a loop, with a soft glow that moves with it. It is not a static outline glow. USAGE <span class="shine" data-text="yoursite.com">yoursite.com</span> (data-text must match the text exactly.) .shine - --shine-base: the normal text color (default #1e1e1e; override per use). - --shine-band: transparent 38%, #e0a400 44%, #ffd000 48%, #fff3a0 50%, #ffd000 52%, #e0a400 56%, transparent 62%. - position relative; display inline-block; isolation isolate; color transparent. - Two background layers: - linear-gradient(100deg, var(--shine-band)) - linear-gradient(var(--shine-base), var(--shine-base)) - background-size: 300% 100%, 100% 100%. - -webkit-background-clip: text; background-clip: text. - animation: shine-sweep 2.6s linear infinite. .shine::before (the moving glow) - content: attr(data-text); position absolute; inset 0; z-index -1; color transparent. - Background: only the band gradient, at background-size 300% 100%, clipped to text. - filter: blur(6px); the same animation; pointer-events none. @keyframes shine-sweep - From background-position 100% 0, 0 0. To 0% 0, 0 0. - Moving the oversized gradient from 100% to 0% carries the band across the text from left to right, with a natural pause between passes. ACCESSIBILITY - @media (prefers-reduced-motion: reduce): turn the animation off for .shine and .shine::before. NOTE - Don't combine it with per-letter transform animations on the same text: background-clip: text won't paint through transformed child elements.

CSS onlyText effectGradient
Live preview

Animations

Scroll-Grow Section

A rounded, inset section that grows to the screen edges (and upward) as you scroll, then eases back partway as it leaves.

Prompt

Build a section that grows to touch the screen edges as you scroll, using GSAP ScrollTrigger with scrub. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Use gsap and gsap/ScrollTrigger (call gsap.registerPlugin(ScrollTrigger)). COMPONENT: GrowSection({ className, children }) — a client component. - Markup: <section ref={outer}> wrapping <div ref={inner} className={className}>{children}</div>. - The section's starting CSS matches the animation's start state, so nothing jumps before hydration: - padding-left/right 80px and padding-top 80px from 768px; 32px each on phones. - The inner div has a 64px radius from 768px (40px on phones) and its own padding (16px; 12px on phones). ANIMATION — set up with gsap.matchMedia() - Run one setup for "(min-width: 768px) and (prefers-reduced-motion: no-preference)" with gutter 80 and radius 64. - Run another for "(max-width: 767px) and (prefers-reduced-motion: no-preference)" with gutter 32 and radius 40. - Reduced motion gets no animation. Call mm.revert() on unmount. - Read the inner div's computed padding-top once (padTop). 1) GROW IN — a timeline with scrollTrigger { trigger: section, start: "top 85%", end: "top 15%", scrub: 0.6 }: - Section: paddingLeft/Right from gutter to 0. - Inner: borderRadius from radius to 0. marginTop from 0 to -gutter. paddingTop from padTop to padTop + gutter. - Use ease "none" and position 0 for both tweens. - The negative margin pulls the top edge up while the matching extra padding keeps the content in place. Total height doesn't change, so the page below never shifts. 2) EASE BACK PARTWAY — a timeline with scrollTrigger { trigger: section, start: "bottom 85%", end: "bottom 15%", scrub: 0.6 }: - With SHRINK = 0.4: section paddingLeft/Right from 0 to gutter × SHRINK, and inner borderRadius from 0 to radius × SHRINK. - Use ease "none" and immediateRender: false on both, so they don't overwrite the grow state on load. - The top is left alone, since it's already off-screen. Everything inside the section (cards, grids) widens with it, because the layout really grows — it's not scaled.

GSAPScrollTriggerScrub
Live preview

UI Components

Lime Email CTA Card

A bright lime card with one small line, an inline contact-form pill, a huge email address and copy/send buttons.

Prompt

Build an email call-to-action card. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. WRAPPER - A section with the side gutter (30px; 20px on phones) and the same top padding. - Inside, a card: background lime #a3f207, text #1e1e1e (fixed, so it works on light and dark pages), radius 40px (28px on phones). - Flex column, centered, text centered. Padding 96px × 40px from 768px, 56px × 20px on phones. Gap 32px (24px on phones). 1. ONE SMALL LINE (not a heading) - A <p>, max-width 36rem, 20px (18px on phones), leading relaxed: "Need something custom? Fill up the [contact form ↗]". - [contact form ↗] is an inline link pill to /contact: 36px tall, padding 0 16px, black background, white 16px medium text, a 14px diagonal arrow, vertical-align middle, 2px side margin. - Then a <br> and "or drop us an email at" at 60% opacity. 2. THE EMAIL — the only big text - A mailto link: clamp(1.5rem, 6vw, 5.5rem), semibold, leading 1, tracking -0.04em, max-width 100%, break-words. - Write it as name@<wbr>domain.com, so on phones it wraps after the @ and never splits mid-word. 3. BUTTONS - "Copy email": #f6f6f8 pill with a copy icon. Uses navigator.clipboard.writeText. On success, shows a check icon and "Copied!" for 2 seconds (aria-live polite). If the clipboard fails, fall back to window.prompt. - "Send email": black pill with white text, a diagonal arrow, and a mailto link. - On phones: stacked, full width, 56px tall. From 640px: side by side, 48px tall, min-width 160px, 14px medium text. No section title or label above it. No hover color changes.

CTACopy to clipboardMailto
Live preview

UI Components

Prompt Product Card

A clickable product card with an autoplaying video preview, purple and lime accents, a heart button, a clamped prompt and a copy button.

Prompt

Build a product card for a prompt library. The whole card links to the product page, a video preview plays while it's on screen, a heart button saves favorites, and a Copy button copies the prompt without navigating. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. - Accents: purple #c084fc and lime #a3f207, used only for small details. DATA: { slug, category, categoryTitle, title, description, tags: string[], prompt, video: "/previews/{slug}.mp4", poster: "/previews/{slug}.webp" } CARD (<article>) - position relative; flex column; gap 20px; radius 28px; background #f6f6f8 (#1c1c1e on dark sections); padding 12px, with 20px at the bottom (24px from 768px). 1. VIDEO PREVIEW (a relative wrapper) - A 16:10 box, radius 16px, overflow hidden, page background color. - Inside: <video src poster muted loop playsInline preload="none">, absolutely filling the box, object-fit cover, aligned to the top. - An IntersectionObserver (threshold 0.25) plays it when it scrolls into view and pauses it when it leaves, so a grid of cards stays light. - Badge in the top-left corner (10px from the top and left): "LIVE PREVIEW", 24px tall, padding 0 10px, lime background, #1e1e1e text, 10px semibold uppercase with wide tracking, an 8px play triangle (path "M2 1.2v7.6L8.6 5Z" in a 10×10 viewBox) and a 6px gap. pointer-events none. 2. Everything below sits in a flex column with a 20px gap and 8px side padding (12px from 768px). 3. TOP ROW (space-between, items at the start) - Left: an 8px round dot (purple for Landing Pages and Web Templates, lime for UI Components and Animations), 8px gap, then the category title (12px medium, uppercase, muted). - Right, 12px apart: a heart favorite button (22px; see "Heart Burst Favorite Button") and a 22px diagonal arrow (path "M6 18 18 6M8 6h10v10", 1.5px stroke). - The heart has position relative and z-index 10, so it sits above the stretched link, and -m-2 p-2 for a bigger tap area. Its click calls preventDefault and stopPropagation. 4. TITLE + DESCRIPTION - An h2 at 24px (28px from 768px), semibold, leading tight, tracking -0.03em. - Its link is a stretched link: put ::after on it with position absolute, inset 0 and a 28px radius, so the whole card is clickable without nesting interactive elements. - Below it, the description at 16px muted, 8px above. 5. PROMPT PREVIEW (pushed to the bottom with margin-top auto, so previews line up across a row) - A wrapper with a 20px radius, the page background color and 16px padding. - First, a label: ">_ PROMPT" in purple, 10px monospace, semibold, uppercase, wide tracking, 8px below it. - Then a <p> with line-clamp 4, 12px monospace, relaxed leading, 70% opacity. - IMPORTANT: put the padding on the wrapper, not on the clamped element. Otherwise the 5th line peeks through the bottom padding. 6. BOTTOM ROW (right under the preview, items aligned to the bottom, space-between) - Wrapped tags: 32px tall, 1px border, padding 0 12px, 12px medium. - A Copy button: position relative, z-index 10 so it sits above the stretched link. 40px tall, padding 0 16px, black pill with white 14px medium text (inverted on dark sections), a copy icon, and a 300ms color transition. - Clicking it copies the full prompt with navigator.clipboard, then shows a check icon and "Copied!" for 2 seconds, and the button turns lime with #1e1e1e text during that time. If the clipboard fails, fall back to window.prompt. - The lime is a state change only. No color changes on hover anywhere on the card. GRID: 1 column on phones, 2 from 768px, 3 from 1024px, 12px gap (16px from 768px). Cards stretch to equal height in each row.

CardVideo previewStretched link
Live preview

Animations

Tech Stack Marquee

An endless, seamless row of tech pills that fades out at both edges — pure CSS, no JavaScript.

Prompt

Build an infinite, seamless "built with" marquee of tech pills. Use pure CSS, no JavaScript. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. ITEMS - Next.js, React, TypeScript, Tailwind CSS, GSAP, ScrollTrigger, Vercel, Geist, Server Actions, Node.js. MARKUP - Outer: a div with aria-label "Built with", width 100%, max-width 768px, overflow hidden. - Fade both edges with mask-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent). - Inside: a track — display flex, width max-content, class "marquee-track". - The track holds TWO identical <ul> lists. The second has aria-hidden="true" so screen readers only read the list once. - Each <ul>: flex, shrink-0, items centered, gap 8px, and padding-right 8px. - The padding makes the gap between the two copies equal to the gap between pills, so the loop has no visible seam. - Each <li>: 36px tall, padding 0 16px, fully rounded, 1px #dcdde2 border, 14px medium, white-space nowrap. ANIMATION - .marquee-track { animation: marquee 30s linear infinite; } - @keyframes marquee { to { transform: translateX(-50%); } } - The track is exactly two copies wide, so moving it by -50% lands copy 2 exactly where copy 1 started, and the loop restarts invisibly. - @media (prefers-reduced-motion: reduce): set the animation to none. PLACEMENT - Centered under the hero heading, inside a flex column with a 20px gap.

CSS onlyMarqueeInfinite loop
Live preview

UI Components

Coming Soon Roll Pill

A disabled nav pill whose label rolls up to “Coming soon” on hover, with a SOON tag on touch screens.

Prompt

Build a disabled "coming soon" pill. It looks like a normal link pill, but it can't be clicked, and on hover its label rolls up and is replaced by "Coming soon". Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. COMPONENT: ComingSoon({ label, className }) — a server component (CSS only). className sets the pill's look so it matches its neighbors, e.g. "flex h-10 items-center justify-center rounded-full bg-[#edeef2]". MARKUP - Outer <span>: role="link", aria-disabled="true", aria-label="{label} — coming soon", cursor not-allowed, user-select none. Make it a named group (group/soon). - It is a span, not an <a> or <button>, so it can't be focused or clicked. - Inside, an aria-hidden <span> that is a CSS grid with overflow hidden and line-height 1.2. - Two children stacked in the same grid cell (col 1 / row 1). The grid sizes itself to the wider of the two, so the pill's width never jumps. 1. The label, text centered: translateY 0, and translateY -100% on group hover. 2. "Coming soon", text centered: translateY 100%, and translateY 0 on group hover. - Both use transition-transform, 300ms, ease-out. TOUCH SCREENS - Touch screens can't hover, so inside the label add a small tag: margin-left 6px, fully rounded, lime #a3f207, text #1e1e1e, 10px semibold uppercase, padding 2px 6px, text "Soon". - It is hidden by default and shown only under @media (hover: none). USAGE - In a dropdown: the same class as the other pills (40px, #edeef2). - In a chip row or mobile menu: the same chip classes plus a dashed border, to hint that it's not available yet. Motion only — no color, background or opacity change on hover.

Disabled stateHoverAccessible
Live preview

Web Templates

Dark Products Catalog

A dark catalog with purple headers, a giant product count, category chips and product pages with copyable prompts.

Prompt

Build a dark-themed product catalog for copy-ready prompts: a listing page, category pages and product pages. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. DESIGN SYSTEM (use exactly): - Page background #edeef2. Surface (light cards, light pills) #f6f6f8. Muted (gray cards) #d9d9dc. Border #dcdde2. - Ink #1e1e1e for text, dark cards and primary buttons. Muted text #8a8a8f. Text on dark: #ffffff. - Accents: purple #c084fc, lime #a3f207. - Font: Geist Sans. Headings semibold with tight tracking (-0.04em) and tight leading (0.95–1.05). - Cards: 28px corner radius. Buttons and chips: fully rounded pills (9999px). - When a card wraps pills, its radius = pill radius + card padding (e.g. 40px pills + 8px padding → 28px card). - Side gutter: 30px from 768px up, 20px on phones. - Links and buttons never change color, background or opacity on hover. DATA (one typed file) - categories: { slug, title, summary }[] — landing-pages, ui-components, web-templates, animations. - products: { slug, category, title, description, tags, prompt }[]. - Helpers: getCategory, getProduct, productsIn. ROUTES - /products, /products/[category] and /products/[category]/[slug]. - Use generateStaticParams with dynamicParams = false, and generateMetadata for titles. DARK THEME FOR THESE ROUTES ONLY - app/products/layout.tsx renders a <style> that overrides the :root tokens: - color-scheme dark; background #111112; surface #1c1c1e; muted #2a2a2d; border #2e2e32; foreground #f2f2f4; muted text #8a8a8f; inverse #111112. - Because it's in the server HTML there's no flash, and it unmounts when you leave /products. - In the same <style>, reset the footer to the light tokens and set color #1e1e1e, so the shared footer keeps its normal look. LISTING / CATEGORY PAGE - main: flex column, gap 12px (16px from 768px), the side gutter, 24px top padding (64px from 768px). 1. Header card - Purple #c084fc, radius 28px, padding 24px (40px from 768px), dark #111112 text. - From 768px it's a row: content on the left, the count on the right, aligned to the bottom. - Left: 12px uppercase label, h1 at clamp(2rem, 5vw, 4rem), semibold, leading 1.02, tracking -0.04em, then the summary in WHITE (16px; 18px from 768px), max-width 36rem. - Right: the product count, padded to 2 digits ("01", "13"), at clamp(4rem, 10vw, 9rem), semibold, leading 0.85, tracking -0.05em, with a 12px uppercase "PROMPTS" label below it ("PROMPT" for one). On phones the label sits beside the number. 2. Category chips - "View all", each category, then a disabled "Agent Skills" (see "Coming Soon Roll Pill") with a dashed border. - Chips: 44px tall, padding 0 20px, 1px border, 14px (16px from 768px) medium. The active one is filled with the foreground color and uses the inverse text color. - On phones it's one sideways-scrolling row with a hidden scrollbar that bleeds to the screen edges. From 768px it wraps. 2b. Search box (a client component that also renders the grid, with the chips passed in as a prop) - From 1280px: one row, chips on the left and the search box right-aligned (300px wide, 360px from 1536px), vertically centered. Below 1280px: the search box is full width above the chips. - role="search" wrapper; <input type="search"> 44px tall, fully rounded, 1px border, surface background, 16px text, 48px padding on both sides, placeholder "Search prompts", aria-label "Search prompts". The border turns lime on focus. Hide the browser's own clear button. - An 18px magnifier icon 20px from the left; when there's text, a 32px round clear button 8px from the right. Escape also clears. - Filtering is instant and client-side: every word typed must appear in the title, description, tags, category name or the category's extra keywords (case-insensitive). A word ending in "s" also matches without it, so "templates" finds "template". On a category page it only searches that category. - Extra keywords per category: Landing Pages "landing page homepage home page hero"; UI Components "ui component element widget"; Web Templates "web template website site page layout"; Animations "animation animated motion effect interaction". So "website" finds Web Templates. - While searching, a small muted line shows "{n} prompts for “{query}”". With no matches: a card saying "No prompts match “{query}”.", a hint, and a lime "Clear search" button. 3. Product grid: see "Prompt Product Card". 1 column on phones, 2 from 768px, 3 from 1024px. - Use grid-cols-1 (minmax(0, 1fr)) on phones so long content can't widen the page. PRODUCT PAGE - Purple header card (same size and padding). From 1024px it's a row with the button pinned to the bottom right. - A 56px round back button: #111112 background, light 24px left arrow, aria-label "Back to {category}". - Then the h1, the description in white, and tags (32px tall, padding 0 12px, white background, #1e1e1e text, 12px medium). - "Copy prompt" button: 56px tall, padding 0 32px, #111112 background with light text, a copy icon. Shows "Copied!" for 2 seconds. - Prompt card: #1c1c1e, radius 28px, padding 12px (16px from 768px). A 12px uppercase "PROMPT" label, then a relative wrapper: - A <pre> with white-space pre-wrap, break-words, radius 20px, #111112 background, monospace 14px (16px from 768px), relaxed leading. - Padding 20px with 72px at the bottom; 32px with 80px at the bottom from 768px. - A "Copy" pill (40px tall, padding 0 16px, light background, dark text) absolutely placed at the bottom right (16px; 24px from 768px), inside the text box. - "More in {category}": a heading at clamp(1.5rem, 2.6vw, 2.25rem), then cards (min-height 160px) for the other products in that category. No hover color changes.

Static paramsDark themeCopy to clipboard
Live preview

Animations

Heart Burst Favorite Button

A heart that pops, rings and bursts into tiny lime and purple dots and hearts when you favorite something.

Prompt

Build a favorite (heart) button with a playful burst animation: when it turns ON, the heart pops, a lime ring pulses out, and 10 tiny lime and purple pieces fly outward and fade. Only the button and its animation; wire onToggle to your own storage. Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. No animation library: React state plus CSS keyframes. COMPONENT: FavoriteButton({ title, defaultOn = false, onToggle, size = 22, className, activeClass = "text-lime" }) — a client component. - State: on (boolean, starts at defaultOn) and burst (a number, starts at 0). - Click: e.preventDefault() and e.stopPropagation() (so it works inside a clickable card). If it's turning ON, do burst + 1. Then flip on and call onToggle?.(nextValue). - <button type="button">: aria-pressed={on}; aria-label "Add {title} to favorites" / "Remove {title} from favorites"; title "Add to favorites" / "Remove from favorites". - Button classes: relative, z-index 10, flex, shrink-0, items/justify center, plus className, plus activeClass while on. - Inside a clickable card, give it -m-2 p-2 so the tap area is bigger without moving the layout. HEART - SVG 24×24 viewBox at size×size, stroke currentColor, stroke-width 1.5, stroke-linejoin round. fill currentColor when on, none when off. - Path: M12 20.5s-7.5-4.6-9.2-9.4C1.7 7.9 3.8 4.5 7.2 4.5c2 0 3.5 1.1 4.8 2.8 1.3-1.7 2.8-2.8 4.8-2.8 3.4 0 5.5 3.4 4.4 6.6-1.7 4.8-9.2 9.4-9.2 9.4Z - Wrap the SVG in <span key={burst} className="flex"> and add the class "fav-pop" when burst > 0 and on. The changing key remounts the span, so the pop replays on every new favorite. BURST (render only when burst > 0 and on) - <span key={"b" + burst} className="fav-burst" aria-hidden="true">: pointer-events none, position absolute, left 50%, top 50%. - Inside: one <span className="fav-ring" /> and 10 pieces. - Pieces: for i = 0..9, angle = (i / 10) × 2π − π/2 (the first one points straight up). Distance = 22px for odd i, 30px for even i. - --tx = cos(angle) × distance px, --ty = sin(angle) × distance px (rounded to 1 decimal), set as inline CSS variables. - Color: #c084fc (purple) for odd i, #a3f207 (lime) for even i. - Every 3rd piece (i % 3 === 0) is a 9×9 SVG of the same heart path, filled with the color. The others are 6×6 round dots (size-1.5, rounded-full) with that background. - animation-delay: (i % 3) × 25ms. CSS (global) @keyframes fav-pop { 0% scale(1); 25% scale(0.75); 55% scale(1.35); 80% scale(0.95); 100% scale(1) } .fav-pop { animation: fav-pop 0.5s cubic-bezier(0.3, 1.5, 0.5, 1); } @keyframes fav-ring { from { transform: translate(-50%, -50%) scale(0.3); opacity: 0.9 } to { transform: translate(-50%, -50%) scale(1.9); opacity: 0 } } .fav-ring { position: absolute; left: 0; top: 0; width: 34px; height: 34px; border-radius: 9999px; border: 2px solid #a3f207; animation: fav-ring 0.5s ease-out forwards; } @keyframes fav-piece { 0% { transform: translate(-50%, -50%) scale(0.2); opacity: 1 } 60% { opacity: 1 } 100% { transform: translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(1); opacity: 0 } } .fav-piece { position: absolute; left: 0; top: 0; opacity: 0; animation: fav-piece 0.65s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; } REDUCED MOTION - @media (prefers-reduced-motion: reduce): no animation on .fav-pop, .fav-ring and .fav-piece; hide the ring and pieces; keep the heart visible (display flex). COLORS - Off: the heart is an outline in the surrounding text color. On: filled with activeClass (lime #a3f207 on dark cards). On a purple header, use a white 56px round button with a purple fill when on. - The color changes only when the state changes, never on hover.

CSS keyframesMicro-interactionAccessible