### Install a Specific VibeCurb Skill Source: https://github.com/yu-369/vibecurb/blob/main/README.md Use this command to install a particular skill pipeline, such as 'visual-redesign'. This makes the skill available for use in your agent. ```bash # Install a specific skill $ npx vibecurb-cli add visual-redesign ``` -------------------------------- ### List Available VibeCurb Pipelines Source: https://github.com/yu-369/vibecurb/blob/main/README.md Use this command to view all the skill pipelines that VibeCurb offers. This helps in identifying the specific skill you need. ```bash # View all available pipelines $ npx vibecurb-cli list ``` -------------------------------- ### Parallax Card HTML Structure Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Example HTML structure for a card intended to be used with the parallax JavaScript. Elements with 'data-depth' attributes control their movement speed. ```html

Feature Title

Description text

``` -------------------------------- ### Scroll Reveal CSS States Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Define CSS states for scroll reveal animations. Elements start hidden and transition to visible when the 'is-visible' class is added by JavaScript, ensuring a smooth animation using defined easing. ```css /* BLUEPRINT: Scroll reveal CSS states WHY: The element starts in its hidden state via CSS. When JS adds .is-visible, the CSS transition takes over. This means elements are hidden by default (no flash of unstyled content), and the transition uses the easing palette for consistency. */ [data-reveal] { opacity: 0; transform: translateY(40px); transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out), filter 0.8s var(--ease-out); will-change: transform, opacity; } [data-reveal].is-visible { opacity: 1; transform: translateY(0); } /* Variant: reveal with blur */ [data-reveal="blur"] { filter: blur(8px); } [data-reveal="blur"].is-visible { filter: blur(0); } /* Variant: reveal with scale */ [data-reveal="scale"] { transform: scale(0.92); } [data-reveal="scale"].is-visible { transform: scale(1); } /* Stagger children within a revealed container */ [data-reveal-stagger] > * { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out); } [data-reveal-stagger].is-visible > *:nth-child(1) { transition-delay: 0ms; opacity: 1; transform: translateY(0); } [data-reveal-stagger].is-visible > *:nth-child(2) { transition-delay: 80ms; opacity: 1; transform: translateY(0); } [data-reveal-stagger].is-visible > *:nth-child(3) { transition-delay: 160ms; opacity: 1; transform: translateY(0); } [data-reveal-stagger].is-visible > *:nth-child(4) { transition-delay: 240ms; opacity: 1; transform: translateY(0); } [data-reveal-stagger].is-visible > *:nth-child(5) { transition-delay: 320ms; opacity: 1; transform: translateY(0); } [data-reveal-stagger].is-visible > *:nth-child(6) { transition-delay: 400ms; opacity: 1; transform: translateY(0); } @media (prefers-reduced-motion: reduce) { [data-reveal] { transform: none !important; filter: none !important; transition: opacity 0.3s ease; } [data-reveal-stagger] > * { transform: none !important; transition: opacity 0.3s ease; transition-delay: 0ms !important; } } ``` -------------------------------- ### Troubleshooting: Rushing to Code Source: https://github.com/yu-369/vibecurb/blob/main/README.md If the agent bypasses design steps and goes straight to code, use this reply to enforce the design read process. Ensure the extraction passes before allowing code generation. ```text Stop. Run the Design Read first. No code until the extraction passes. ``` -------------------------------- ### Troubleshooting: Generic Dashboard Output Source: https://github.com/yu-369/vibecurb/blob/main/README.md If the agent produces a standard dashboard template, it has likely dropped the context. Use this reply to remind the agent to re-read and apply the constraints from the skill file. ```text You ignored the skill file. Re-read it and apply the drift constraints. ``` -------------------------------- ### GSAP Spring-like Easing Equivalents Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Replicate the feel of spring animations in GSAP using its CustomEase plugin or standard power easings. For true spring physics, the gsap-spring plugin is recommended. ```javascript /* BLUEPRINT: GSAP spring-like easing WHY: GSAP doesn't use spring physics natively, but its CustomEase plugin can replicate the feel. For standard use, these "power" easings are the closest GSAP equivalents. */ // snappy: "power3.out" or CustomEase // smooth: "power2.inOut" // bouncy: "back.out(1.7)" — the 1.7 controls overshoot amount // dramatic: "expo.inOut" // snap: "power4.out" // For true springs in GSAP, use the gsap-spring plugin: // gsap.to(".element", { x: 100, ease: "spring({stiffness: 400, damping: 30})" }); ``` -------------------------------- ### VibeCurb Prompt Template Source: https://github.com/yu-369/vibecurb/blob/main/README.md Use this template to structure prompts for AI agents, ensuring all aesthetic and contextual constraints are defined before requesting a deliverable. This helps prevent generic or hallucinated design choices. ```text Based on the skill above, generate the for a . The website is for a . Because of that, I want the visual to feel , with . Make it feel . . Think , utilizing a . Keep it in mode, using . I want it to look . Generate the . ``` -------------------------------- ### JavaScript Button Compression with Spring Physics Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Implement a button that compresses with spring physics on hover and press, mimicking physical button feedback. Requires CSS variables for spring easing. ```javascript function initPressureButtons() { if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; document.querySelectorAll('[data-pressure]').forEach((btn) => { const depth = parseFloat(btn.dataset.pressure) || 0.97; btn.addEventListener('mouseenter', () => { btn.style.transform = `scale(${depth})`; btn.style.boxShadow = 'inset 0 2px 8px rgba(0,0,0,0.15), 0 1px 2px rgba(0,0,0,0.1)'; btn.style.transition = `transform 0.5s var(--spring-snappy), box-shadow 0.3s var(--ease-snap)`; btn.style.filter = 'brightness(1.05)'; }); btn.addEventListener('mouseleave', () => { btn.style.transform = 'scale(1)'; btn.style.boxShadow = ''; btn.style.transition = `transform 0.55s var(--spring-snappy), box-shadow 0.4s var(--ease-out)`; btn.style.filter = 'brightness(1)'; }); btn.addEventListener('mousedown', () => { btn.style.transform = `scale(${depth - 0.03})`; // deeper press btn.style.boxShadow = 'inset 0 3px 12px rgba(0,0,0,0.25), 0 0 0 rgba(0,0,0,0)'; btn.style.transition = 'transform 0.08s ease, box-shadow 0.08s ease'; }); btn.addEventListener('mouseup', () => { btn.style.transform = `scale(${depth})`; btn.style.boxShadow = 'inset 0 2px 8px rgba(0,0,0,0.15), 0 1px 2px rgba(0,0,0,0.1)'; btn.style.transition = `transform 0.5s var(--spring-bouncy), box-shadow 0.3s var(--ease-snap)`; }); }); } ``` -------------------------------- ### Prompt Anti-Patterns and Alternatives Source: https://github.com/yu-369/vibecurb/blob/main/skills/imagegen-frontend/SKILL.md This table lists common AI image generation patterns to avoid and provides guidance on what to specify instead. Explicitly stating negative constraints is crucial for effective AI output. ```plaintext | Banned Pattern | Why it's banned | What to say instead | |---|---|---| | **Purple/blue AI gradient hero** | Every AI-generated "tech" image defaults to this. It screams "generated." | Specify the exact palette from Phase 2. Add "no purple, no blue gradient backgrounds." | | **Floating translucent blobs** | The AI's version of "atmosphere" — meaningless glass orbs floating in space | Specify concrete atmosphere: grain, radial glow, tonal gradient, or photographic background | | **Generic dashboard card grid** | AI loves generating 6-8 identical cards with line charts | Specify the exact component from Phase 2's signature set. Describe its unique geometry | | **Centered text over gradient** | Safe, generic, says nothing about the brand | Specify the exact composition anchor from Phase 2. Force an asymmetric or editorial layout | | **"Luxury" = beige serif on cream** | The AI's entire luxury vocabulary | Specify the actual luxury signals: restrained spacing, tactile texture, considered typography weight | | **"Creative" = messy and unreadable** | Chaos ≠ creativity | Specify structured asymmetry: deliberate off-grid placement with clear reading order | | **Tiny illegible text** | AI generates decorative text that no one can read | Specify minimum type scale: "heading must be legible and dominant, minimum 60pt equivalent" | | **Identical section layouts** | Every section looks the same — same split, same proportion | Use the composition anchor assignments from Phase 2 — each section has a different anchor | | **Stock photo energy** | Generic business people shaking hands, laptop on desk | Specify the exact photographic direction: subject, color grade, mood, crop style | ``` -------------------------------- ### Generate Illustration with Detailed Prompt Source: https://github.com/yu-369/vibecurb/blob/main/skills/pixel-perfect/SKILL.md When using the generate_image tool for illustrations, provide a detailed prompt that includes style, colors, stroke quality, composition, and mood. ```text generate_image("organic hand-painted pink brush stroke with visible texture, diagonal across white background, coral/hot-pink color, similar to expressive abstract art") ``` -------------------------------- ### Style Input Placeholder Source: https://github.com/yu-369/vibecurb/blob/main/skills/visual-redesign/SKILL.md Sets a custom color and opacity for input placeholder text, improving visual consistency and user guidance. ```css color: var(--color-text-3); opacity: 0.7 ``` -------------------------------- ### Hero Heading CSS Blueprint Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-hero/SKILL.md Responsive hero heading styling using clamp() for fluid sizing without breakpoints. Negative letter-spacing and reduced line-height are crucial for large text. ```css /* BLUEPRINT: Hero heading WHY: clamp() makes the heading responsive without breakpoints. Negative letter-spacing is critical at large sizes — positive tracking on massive text creates a loose, amateurish feel. line-height below 1.0 lets ascenders and descenders overlap slightly, which looks intentional at display scale. */ .hero-heading { font-size: clamp(2.5rem, 7vw, 8rem); font-weight: 700; letter-spacing: -0.03em; line-height: 0.95; text-wrap: balance; max-width: 18ch; /* prevents 4+ line wraps */ } /* For 1-3 word headings, go larger */ .hero-heading--short { font-size: clamp(4rem, 14vw, 18rem); letter-spacing: -0.05em; line-height: 0.85; } ``` -------------------------------- ### Perspective Card Shelf CSS Blueprint Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-hero/SKILL.md Provides CSS for creating a perspective card shelf effect, enabling depth and rotation for elements. Essential for layered depth compositions. ```css /* BLUEPRINT: Perspective card shelf WHY: perspective-origin centers the vanishing point. preserve-3d lets child transforms create real depth. backface-visibility prevents render flicker on rotation. */ .perspective-container { perspective: 1200px; perspective-origin: center center; } .depth-card { transform-style: preserve-3d; transition: transform 0.8s cubic-bezier(0.16, 1, 0.3, 1); backface-visibility: hidden; } ``` -------------------------------- ### Prompt Blueprint Structure Source: https://github.com/yu-369/vibecurb/blob/main/skills/imagegen-frontend/SKILL.md This is the standard structure for section prompts, ensuring all necessary details are included for generation-ready instructions. Fill in every field to avoid generic output. ```plaintext PROMPT BLUEPRINT — Section [N] of [Total]: [Section Name] ───────────────────────────────────────────────────────── FRAME: Format: horizontal website section, 16:9 aspect ratio Viewport: 1440×900 desktop browser frame Render style: [photorealistic UI mockup / flat design comp / editorial layout] COMPOSITION: Anchor: [from Phase 2 — e.g., "centered statement" or "bottom-left over background"] Visual weight: [where the eye lands first — e.g., "center-left, massive heading"] Reading flow: [how the eye moves — e.g., "heading → subtext → CTA → background visual"] TYPOGRAPHY: Heading: [exact description — e.g., "massive compressed sans-serif, all-caps, approximately 80pt equivalent, tight letter-spacing, 2 lines max"] Subtext: [e.g., "16pt equivalent, regular weight, muted color, max 20 words, 1.5 line-height"] Eyebrow: [e.g., "11pt monospace, uppercase, wide letter-spacing, muted opacity"] CTA text: [e.g., "14pt, medium weight, uppercase, inside pill button"] PALETTE: Background: [exact description — e.g., "#0a0a0a deep charcoal with subtle radial glow from center"] Text primary: [e.g., "#f5f5f5 warm off-white"] Text secondary: [e.g., "rgba(255,255,255,0.5) muted"] Accent: [e.g., "#E8A04A warm amber — used on CTA only"] BACKGROUND MODE: [from Phase 2 — e.g., "full-bleed cinematic photograph of server rack room, cool blue-teal color grade, 40% dark overlay for text readability"] CTA: Style: [from Phase 2 — e.g., "solid pill, amber background, dark text"] Placement: [e.g., "centered below subtext, 32px gap"] Count: [1 — never more in a hero] ATMOSPHERE: [e.g., "subtle film grain overlay at 3% opacity, soft radial ambient glow from top-center, no hard shadows"] CONTENT (placeholder text): Eyebrow: [e.g., "INFRASTRUCTURE"] Heading: [e.g., "Build without limits."] Subtext: [e.g., "The platform for teams who ship fast."] CTA: [e.g., "Get Started →"] WHAT THIS IS NOT: [Explicit anti-patterns — e.g., "NOT a generic dark hero with purple AI glow. NOT a dashboard screenshot. NOT centered text over a gradient blob."] MOTION IMPLIED: [from Phase 2 — e.g., "staggered float-up energy: the heading, subtext, and CTA appear at slightly different vertical offsets as if mid-cascade"] ``` -------------------------------- ### CSS for Image Asset Container Source: https://github.com/yu-369/vibecurb/blob/main/skills/pixel-perfect/SKILL.md This CSS blueprint demonstrates how to style an image asset within a card or container. It uses object-fit: cover to ensure the image fills the space without distortion and object-position to align the focal point. ```css /* BLUEPRINT: Image asset inside a card or container WHY: object-fit:cover ensures the image fills the space without distortion. object-position lets you align the focal point of the image to match the reference. */ .asset-container { position: relative; overflow: hidden; border-radius: var(--radius-card); /* match card radius */ } .asset-image { width: 100%; height: 100%; object-fit: cover; object-position: center; /* adjust to match reference focal point */ } ``` -------------------------------- ### CSS for Shimmer Skeleton Loading Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Provides styles for a shimmering skeleton loading state, using a sweeping gradient to indicate content is loading. Includes variants for light and dark modes, and respects reduced motion preferences. Best for placeholder content during asynchronous data fetching. ```css /* BLUEPRINT: Shimmer loading state that sweeps across elements WHY: While content loads, placeholder shapes with a sweeping shimmer convey progress better than a spinner. The gradient moves via translateX animation. The shimmer angle (-20deg) creates a natural light-sweep direction. This runs ONLY until real content replaces it — never as a permanent effect. Best on: cards, images, text blocks during async data fetch. */ .shimmer { background: var(--color-surface, #e0e0e0); background-image: linear-gradient( -20deg, transparent 25%, rgba(255, 255, 255, 0.5) 50%, transparent 75% ); background-size: 200% 100%; animation: shimmer-sweep 1.5s ease-in-out infinite; border-radius: var(--radius-card, 8px); } @keyframes shimmer-sweep { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } /* Dark mode variant */ .shimmer--dark { background: rgba(255, 255, 255, 0.05); background-image: linear-gradient( -20deg, transparent 25%, rgba(255, 255, 255, 0.08) 50%, transparent 75% ); background-size: 200% 100%; animation: shimmer-sweep 1.5s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .shimmer, .shimmer--dark { animation: none; } } ``` -------------------------------- ### Smooth Scrolling with Lenis Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Implement smooth, configurable inertia scrolling using the Lenis library. Set `lerp` for smoothness and `duration` for scroll speed. Ensure `smoothTouch` is false to maintain native mobile scroll feel. ```javascript import Lenis from "@studio-freight/lenis"; const lenis = new Lenis({ lerp: 0.1, duration: 1.2, smoothWheel: true, smoothTouch: false, wheelMultiplier: 1, touchMultiplier: 2, }); function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); ``` -------------------------------- ### CSS Entry Animations with Custom Properties Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Defines CSS keyframes for 'enter-up', 'enter-scale', and 'enter-fade' animations. These can be applied to elements using classes and controlled via inline custom properties for staggering delays. Includes a media query for reduced motion. ```css @keyframes enter-up { from { opacity: 0; transform: translateY(var(--enter-y, 24px)); filter: blur(var(--enter-blur, 6px)); } to { opacity: 1; transform: translateY(0); filter: blur(0); } } @keyframes enter-scale { from { opacity: 0; transform: scale(var(--enter-scale, 0.95)); filter: blur(var(--enter-blur, 4px)); } to { opacity: 1; transform: scale(1); filter: blur(0); } } @keyframes enter-fade { from { opacity: 0; } to { opacity: 1; } } .enter-up { animation: enter-up 0.7s var(--ease-out) both; animation-delay: var(--stagger, 0ms); } .enter-scale { animation: enter-scale 0.6s var(--ease-out) both; animation-delay: var(--stagger, 0ms); } .enter-fade { animation: enter-fade 0.5s var(--ease-out) both; animation-delay: var(--stagger, 0ms); } /* Stagger via inline custom properties in HTML:

*/ @media (prefers-reduced-motion: reduce) { .enter-up, .enter-scale { animation: enter-fade 0.3s ease both; animation-delay: 0ms; } } ``` -------------------------------- ### Inline Hero Image CSS Blueprint Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-hero/SKILL.md Provides CSS for styling inline hero images, ensuring they match the x-height of text and act as visual punctuation. Use this for creative agency hero sections. ```css /* BLUEPRINT: Inline hero images WHY: The images must match the x-height of the surrounding text. They are punctuation, not focal elements. Making them too large turns the heading into a gallery instead of a sentence. */ .inline-hero-img { display: inline-block; width: clamp(3rem, 5vw, 5rem); height: clamp(2rem, 3.5vw, 3.5rem); border-radius: 9999px; /* pill shape */ object-fit: cover; vertical-align: middle; margin-inline: 0.25em; } ``` -------------------------------- ### Generate Placeholder Image with Picsum Photos Source: https://github.com/yu-369/vibecurb/blob/main/skills/pixel-perfect/SKILL.md Use this method to generate a placeholder image when a specific photograph is not available. Replace '{descriptive-keyword}' with a term relevant to the desired image content. ```text picsum.photos/seed/{descriptive-keyword}/{w}/{h} ``` -------------------------------- ### CSS for Universal Interactive Transition Source: https://github.com/yu-369/vibecurb/blob/main/skills/pixel-perfect/SKILL.md Applies a smooth transition effect to all interactive elements for consistent visual feedback on hover, focus, or other state changes. ```css /* Universal interactive transition */ a, button, [role="button"], input, select, textarea { transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); } ``` -------------------------------- ### HTML Usage for Scroll Reveal Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Demonstrates how to apply the 'data-reveal' attribute in HTML to trigger scroll animations. Different attribute values can be used for variants like blur or scale effects. ```html

Section heading

Blurs into focus

Card 1
Card 2
Card 3
``` -------------------------------- ### Handling 'Gray Zone' Elements in Visual Redesign Source: https://github.com/yu-369/vibecurb/blob/main/skills/visual-redesign/SKILL.md Carefully manage elements that blend logic and style. When in doubt, prioritize preserving the existing structure and logic over aesthetic refactoring to prevent bugs. ```markdown | Element | Sacred or Slop? | Rule | |---|---| --- | | `className={isActive ? 'active' : ''}` | **Both** — logic is sacred, class names are slop | Keep the ternary. Change only the class name values: `className={isActive ? 'nav-link--active' : 'nav-link'}` | | `style={{ display: isOpen ? 'block' : 'none' }}` | **Sacred** — this is conditional visibility logic | Do NOT replace with CSS classes. The inline style is driven by state. Leave it. Add your styles alongside it | | `{items.map((item) => )}` | **Sacred** — the map, key, and data flow are logic | Style the Card component's internals. Do not change the map structure or key assignment | | `ref={containerRef}` | **Sacred** — ref assignments drive JS behavior | Never remove, move, or rename refs | | `aria-*` attributes | **Sacred** — accessibility attributes are functional | Never remove. You may add missing ones | | `data-*` attributes | **Probably sacred** — often used by JS/tests | Never remove unless confirmed unused | | `id` attributes | **Probably sacred** — may be used by JS selectors | Never change unless confirmed unused | | `onClick={() => setOpen(!open)}` | **Sacred** — the handler is logic | Style the element. Do not touch the handler | | `
` that wraps conditional content | **Sacred** — the div may exist for rendering reasons | Do not remove "unnecessary" wrapper divs unless you've confirmed they're purely presentational | ``` -------------------------------- ### CSS View Transitions API for Page Transitions Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Defines CSS animations for root element transitions (fade-out/fade-in) and custom element transitions (e.g., hero image). Uses ::view-transition-old and ::view-transition-new pseudo-elements. ```css ::view-transition-old(root) { animation: fade-out 0.3s var(--ease-in-out); } ::view-transition-new(root) { animation: fade-in 0.3s var(--ease-in-out); } @keyframes fade-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.98); } } @keyframes fade-in { from { opacity: 0; transform: scale(1.02); } to { opacity: 1; transform: scale(1); } } /* Element-level transitions (e.g., hero image persists across pages) */ .hero-image { view-transition-name: hero-image; } ::view-transition-old(hero-image) { animation: none; mix-blend-mode: normal; } ::view-transition-new(hero-image) { animation: none; mix-blend-mode: normal; } ``` -------------------------------- ### JavaScript Implementation of View Transitions API Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Triggers page transitions using `document.startViewTransition`. Fetches new content, swaps it into the DOM, updates the title and URL. Falls back to direct navigation if the API is not supported. ```javascript function navigateWithTransition(url) { if (!document.startViewTransition) { window.location.href = url; return; } document.startViewTransition(async () => { const response = await fetch(url); const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); // Swap the main content document.querySelector("main").innerHTML = doc.querySelector("main").innerHTML; // Update the title document.title = doc.title; // Update URL history.pushState({}, "", url); }); } ``` -------------------------------- ### Off-Canvas Menu Slide-In Animation (CSS) Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Animates an off-canvas menu sliding in from the right with staggered link entry. Uses `visibility` and `pointer-events` for animation compatibility. Requires CSS variables for easing functions. ```css .mobile-menu { position: fixed; inset: 0; background: var(--color-bg); transform: translateX(100%); transition: transform 0.5s var(--ease-out); visibility: hidden; pointer-events: none; z-index: 100; } .mobile-menu.is-open { transform: translateX(0); visibility: visible; pointer-events: auto; } .mobile-menu .menu-link { opacity: 0; transform: translateX(30px); transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out); } .mobile-menu.is-open .menu-link:nth-child(1) { transition-delay: 100ms; opacity: 1; transform: translateX(0); } .mobile-menu.is-open .menu-link:nth-child(2) { transition-delay: 160ms; opacity: 1; transform: translateX(0); } .mobile-menu.is-open .menu-link:nth-child(3) { transition-delay: 220ms; opacity: 1; transform: translateX(0); } .mobile-menu.is-open .menu-link:nth-child(4) { transition-delay: 280ms; opacity: 1; transform: translateX(0); } .mobile-menu.is-open .menu-link:nth-child(5) { transition-delay: 340ms; opacity: 1; transform: translateX(0); } ``` -------------------------------- ### 3D Card Tilt Effect Following Cursor Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Implements a 3D tilt effect on cards that follows the cursor's position, creating a tangible depth feel. Rotation is clamped to prevent extreme angles, and a glare overlay simulates light reflection. `getBoundingClientRect` is used on `mousemove` for performance. ```javascript /* BLUEPRINT: 3D tilt card that follows cursor position WHY: The card tilts toward the cursor, creating a tangible depth feel. The rotation is clamped to ±8deg to prevent extreme angles. The glare overlay simulates light reflection. getBoundingClientRect() is called on mousemove — this is acceptable because it only fires on hovered cards (1-2 elements), not on scroll (hundreds of elements). */ function initTiltCards() { document.querySelectorAll("[data-tilt]").forEach((card) => { const maxTilt = 8; // degrees card.addEventListener("mousemove", (e) => { const rect = card.getBoundingClientRect(); const x = (e.clientX - rect.left) / rect.width; // 0 to 1 const y = (e.clientY - rect.top) / rect.height; // 0 to 1 const rotateX = (0.5 - y) * maxTilt; // tilt up/down const rotateY = (x - 0.5) * maxTilt; // tilt left/right card.style.transform = ` perspective(800px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.02, 1.02, 1.02) `; }); card.addEventListener("mouseleave", () => { card.style.transform = "perspective(800px) rotateX(0) rotateY(0) scale3d(1,1,1)"; card.style.transition = "transform 0.6s var(--ease-out)"; }); card.addEventListener("mouseenter", () => { card.style.transition = "transform 0.1s ease-out"; }); }); } ``` -------------------------------- ### Tab Switch with Sliding Indicator (JavaScript) Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Initializes tab functionality and moves a sliding indicator to the active tab. The indicator's width and position are dynamically calculated. Call `initTabs()` after the DOM is ready. ```javascript function initTabs() { const tabContainer = document.querySelector("[data-tabs]"); const indicator = tabContainer.querySelector(".tab-indicator"); const tabs = tabContainer.querySelectorAll("[data-tab]"); function moveIndicator(tab) { const rect = tab.getBoundingClientRect(); const containerRect = tabContainer.getBoundingClientRect(); indicator.style.width = `${rect.width}px`; indicator.style.transform = `translateX(${rect.left - containerRect.left}px)`; } tabs.forEach((tab) => { tab.addEventListener("click", () => { tabs.forEach((t) => t.classList.remove("active")); tab.classList.add("active"); moveIndicator(tab); }); }); // Initialize on the active tab const activeTab = tabContainer.querySelector("[data-tab].active"); if (activeTab) moveIndicator(activeTab); } ``` -------------------------------- ### Default Image Generation Configuration Dials Source: https://github.com/yu-369/vibecurb/blob/main/skills/imagegen-frontend/SKILL.md These are the global default settings that calibrate the image generation engine. They can be dynamically adapted based on user briefs. ```plaintext DESIGN_VARIANCE: 8 (1=rigid/symmetrical, 10=artsy/asymmetric) VISUAL_DENSITY: 4 (1=airy/gallery-like, 10=packed/intense) ART_DIRECTION: 8 (1=safe commercial, 10=bold creative statement) IMPLEMENTATION_CLARITY: 9 (1=loose moodboard, 10=very codeable UI reference) IMAGE_USAGE_PRIORITY: 9 (1=mostly typographic, 10=strongly image-led) SPACING_GENEROSITY: 8 (1=compact/tight, 10=very spacious/breathable) LAYOUT_VARIATION: 8 (1=same anchor repeats, 10=bold composition variety) CONVERSION_DISCIPLINE: 8 (1=pure art moodboard, 10=clear funnel + design balance) ``` -------------------------------- ### Preloader Controller JavaScript Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Manages the preloader's progress animation, counter display, and exit sequence. It tracks font and image loading to determine completion. Initialize this script after the DOM is ready. ```javascript /* BLUEPRINT: Preloader controller WHY: We simulate loading progress based on font + image readiness. The counter formats to 3 digits (001...100). When all resources are loaded, we trigger the exit sequence and then fire the hero entry animation. */ class Preloader { constructor() { this.counter = document.querySelector(".preloader-counter"); this.line = document.querySelector(".preloader-line"); this.preloader = document.querySelector(".preloader"); this.progress = 0; this.target = 0; } start() { // Track actual resource loading const promises = [ document.fonts.ready, ...Array.from(document.images).map( (img) => img.complete ? Promise.resolve() : new Promise((res) => { img.onload = res; img.onerror = res; }) ), ]; // Animate counter smoothly const tick = () => { this.progress += (this.target - this.progress) * 0.08; const rounded = Math.round(this.progress); this.counter.textContent = String(rounded).padStart(3, "0"); this.line.style.setProperty("--progress", this.progress / 100); if (rounded < 100) { requestAnimationFrame(tick); } else { this.complete(); } }; // Simulate progress stages setTimeout(() => { this.target = 30; }, 100); setTimeout(() => { this.target = 60; }, 400); setTimeout(() => { this.target = 80; }, 700); Promise.all(promises).then(() => { this.target = 100; }); requestAnimationFrame(tick); } complete() { setTimeout(() => { this.preloader.classList.add("is-done"); // Trigger hero entry animation after preloader exits setTimeout(() => { document.body.classList.add("is-loaded"); }, 800); }, 300); } } // Initialize document.addEventListener("DOMContentLoaded", () => { new Preloader().start(); }); ``` -------------------------------- ### CSS for Staggered Entry Animation Source: https://github.com/yu-369/vibecurb/blob/main/skills/pixel-perfect/SKILL.md Applies a fade-in and slide-up animation with a blur effect for elements entering the viewport. Includes a fallback for reduced motion preferences. ```css /* BLUEPRINT: Staggered entry animation WHY: Elements that fade+slide in feel intentional. The blur-to-sharp adds perceived quality. prefers-reduced-motion disables for accessibility. */ @keyframes enter { from { opacity: 0; transform: translateY(24px); filter: blur(6px); } to { opacity: 1; transform: translateY(0); filter: blur(0); } } .animate-in { animation: enter 0.7s cubic-bezier(0.16, 1, 0.3, 1) both; } .animate-in:nth-child(1) { animation-delay: 0.05s; } .animate-in:nth-child(2) { animation-delay: 0.15s; } .animate-in:nth-child(3) { animation-delay: 0.25s; } .animate-in:nth-child(4) { animation-delay: 0.35s; } @media (prefers-reduced-motion: reduce) { .animate-in { animation: none; opacity: 1; transform: none; filter: none; } } ``` -------------------------------- ### Minimal Progress Preloader CSS Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Defines the styles for a preloader with an expanding line and a counter. The preloader animates its exit using clip-path. Use this for a premium loading experience. ```css /* BLUEPRINT: Minimal preloader with line expansion WHY: A single expanding line is more premium than a spinner. The line grows from center (scaleX 0 -> 1) while a counter ticks up. When loading completes, the preloader lifts away with a clip-path wipe. */ .preloader { position: fixed; inset: 0; background: var(--color-bg); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 10000; transition: clip-path 0.8s var(--ease-dramatic); clip-path: inset(0); } .preloader.is-done { clip-path: inset(0 0 100% 0); /* wipes upward */ pointer-events: none; } .preloader-line { width: 120px; height: 1px; background: var(--color-text-3); position: relative; overflow: hidden; } .preloader-line::after { content: ''; position: absolute; inset: 0; background: var(--color-text); transform: scaleX(0); transform-origin: left; transition: transform 0.3s linear; } /* JS sets --progress from 0 to 1 */ .preloader-line::after { transform: scaleX(var(--progress, 0)); } .preloader-counter { font-family: var(--font-mono, monospace); font-size: 0.75rem; letter-spacing: 0.1em; color: var(--color-text-3); margin-top: 1rem; } ``` -------------------------------- ### Custom Transition Easing Source: https://github.com/yu-369/vibecurb/blob/main/skills/visual-redesign/SKILL.md Replaces the default 'ease-in-out' transition with a custom cubic-bezier curve for a more unique and engaging animation feel. ```css transition: all 0.3s cubic-bezier(0.22, 1, 0.36, 1) ``` -------------------------------- ### Spring Physics Easing Palette via CSS linear() Source: https://github.com/yu-369/vibecurb/blob/main/skills/awwwards-motion/SKILL.md Defines a set of CSS custom properties for various spring physics-based easing curves using `linear()`. These are intended for browsers supporting `linear()` and provide realistic motion with overshoot and settle. Use the highest tier your browser support allows. ```css :root { /* 1. APPLE SNAPPY SPRING — Primary entrance/reveal easing Physics: mass=1, stiffness=400, damping=30 Character: Explosive start, tiny overshoot (~2%), soft settle. This is the iOS sheet-present / notification-arrive curve. Use on: hero entries, scroll reveals, modal opens, everything that "arrives" on screen. This is your DEFAULT curve. */ --spring-snappy: linear( 0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%, 0.938 16.7%, 1.017 19.4%, 1.067 22.5%, 1.089 26.0%, 1.079 30.3%, 1.049 36.0%, 1.024 42.6%, 1.011 50.3%, 1.004 59.2%, 1.001 69.3%, 1 ); --spring-snappy-duration: 0.55s; /* 2. APPLE SMOOTH SPRING — State changes, position shifts Physics: mass=1, stiffness=200, damping=24 Character: Gentle acceleration, visible overshoot (~5%), two-phase settle. Feels like a precision instrument. This is the iOS page-transition / tab-switch curve. Use on: page transitions, tab switches, carousel slides, anything moving from position A to position B. */ --spring-smooth: linear( 0, 0.004, 0.016 2.3%, 0.063 4.7%, 0.141 7.2%, 0.25 9.9%, 0.601 16.5%, 0.815 21.0%, 0.929 25.2%, 0.987 29.0%, 1.025 33.5%, 1.042 38.0%, 1.04 43.5%, 1.027 50.0%, 1.013 57.5%, 1.005 67.0%, 1.001 79.0%, 1 ); --spring-smooth-duration: 0.7s; /* 3. APPLE BOUNCY SPRING — Playful micro-interactions Physics: mass=1, stiffness=500, damping=18 Character: Very fast, pronounced overshoot (~12%), visible bounce-settle. Feels playful, energetic, delightful. Use SPARINGLY on: toggles, like buttons, notification pops, small badges, emoji reactions. NEVER on large elements. */ --spring-bouncy: linear( 0, 0.014, 0.055 1.8%, 0.218 3.7%, 0.867 8.5%, 1.085 10.7%, 1.212 12.9%, 1.264 15.0%, 1.262 17.0%, 1.217 19.5%, 1.098 24.0%, 1.035 28.5%, 0.993 33.0%, 0.981 38.0%, 0.988 45.0%, 0.998 55.0%, 1.001 68.0%, 1 ); --spring-bouncy-duration: 0.5s; /* 4. MATERIAL 3 EMPHASIZED — Google's expressive motion standard Source: Material Design 3 motion spec (legacy cubic-bezier fallback) Character: Very slow start, dramatic acceleration, gentle decelerate. This is the M3 "emphasized" transition for container transforms, shared element transitions, and FAB expansions. Use on: container morphs, expand/collapse, shared transitions. */ --m3-emphasized: cubic-bezier(0.05, 0.7, 0.1, 1.0); --m3-emphasized-duration: 0.5s; /* 5. MATERIAL 3 EMPHASIZED as SPRING — for spring-capable contexts Physics: mass=1, stiffness=300, damping=22 The spring equivalent of M3 Emphasized — with the overshoot that Google's spec now recommends via their spring system. */ --m3-spring: linear( 0, 0.007, 0.029 2.0%, 0.118 4.2%, 0.508 10.9%, 0.797 15.4%, 0.951 19.2%, 1.029 22.2%, 1.074 25.6%, 1.088 29.2%, 1.075 33.6%, 1.045 39.5%, 1.02 46.5%, 1.007 55.0%, 1.001 66.0%, 1 ); --m3-spring-duration: 0.6s; } ```