All skills

Page transitions library for creating fluid, smooth transitions between website pages. Use this skill when implementing page transitions, creating SPA-like experiences, adding animated route changes, or building websites with smooth navigation. Triggers on tasks involving Barba.js, page transitions, routing, view management, transition hooks, GSAP integration, or smooth page navigation. Works with gsap-scrolltrigger for transition animations.

Use this Skill: https://skilld.dev/gh/freshtechbro/claudedesignskills/barba-js

This session only. Nothing lands on disk.

referencestransition_patterns.md

≈4.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Barba.js Transition Patterns Library

Copy-paste transition implementations for common page transition effects.

Table of Contents


Fade Transitions

Simple Fade

Classic fade out → fade in:

{
  name: 'fade',

  async leave({ current }) {
    await gsap.to(current.container, {
      opacity: 0,
      duration: 0.5,
      ease: 'power2.inOut'
    });
  },

  async enter({ next }) {
    gsap.set(next.container, { opacity: 0 });

    await gsap.to(next.container, {
      opacity: 1,
      duration: 0.5,
      ease: 'power2.inOut'
    });
  }
}

Crossfade (Sync)

Both pages fade simultaneously:

{
  name: 'crossfade',
  sync: true,

  leave({ current }) {
    return gsap.to(current.container, {
      opacity: 0,
      duration: 0.8,
      ease: 'power2.inOut'
    });
  },

  enter({ next }) {
    return gsap.from(next.container, {
      opacity: 0,
      duration: 0.8,
      ease: 'power2.inOut'
    });
  }
}

Fade with Scale

Fade + subtle zoom:

{
  name: 'fade-scale',

  async leave({ current }) {
    await gsap.to(current.container, {
      opacity: 0,
      scale: 0.95,
      duration: 0.5,
      ease: 'power2.in'
    });
  },

  async enter({ next }) {
    await gsap.fromTo(next.container,
      {
        opacity: 0,
        scale: 1.05
      },
      {
        opacity: 1,
        scale: 1,
        duration: 0.6,
        ease: 'power2.out'
      }
    );
  }
}

Slide Transitions

Horizontal Slide

Old page slides left, new page slides in from right:

{
  name: 'slide-horizontal',
  sync: true,

  leave({ current }) {
    return gsap.to(current.container, {
      x: '-100%',
      duration: 0.7,
      ease: 'power3.inOut'
    });
  },

  enter({ next }) {
    gsap.set(next.container, { x: '100%' });

    return gsap.to(next.container, {
      x: '0%',
      duration: 0.7,
      ease: 'power3.inOut'
    });
  }
}

Vertical Slide

Old page slides up, new page slides in from bottom:

{
  name: 'slide-vertical',
  sync: true,

  leave({ current }) {
    return gsap.to(current.container, {
      y: '-100%',
      duration: 0.7,
      ease: 'power3.inOut'
    });
  },

  enter({ next }) {
    gsap.set(next.container, { y: '100%' });

    return gsap.to(next.container, {
      y: '0%',
      duration: 0.7,
      ease: 'power3.inOut'
    });
  }
}

Direction-Based Slide

Slide direction based on browser history:

{
  name: 'slide-smart',
  sync: true,

  leave({ current }) {
    const direction = barba.history.direction;
    const isBack = direction === 'back';

    return gsap.to(current.container, {
      x: isBack ? '100%' : '-100%',
      duration: 0.6,
      ease: 'power2.inOut'
    });
  },

  enter({ next }) {
    const direction = barba.history.direction;
    const isBack = direction === 'back';

    gsap.set(next.container, {
      x: isBack ? '-100%' : '100%'
    });

    return gsap.to(next.container, {
      x: '0%',
      duration: 0.6,
      ease: 'power2.inOut'
    });
  }
}

CSS Required (for sync mode):

[data-barba="wrapper"] {
  position: relative;
  overflow: hidden;
}

[data-barba="container"] {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

Scale Transitions

Zoom Out → Zoom In

{
  name: 'zoom',

  async leave({ current }) {
    await gsap.to(current.container, {
      opacity: 0,
      scale: 0.8,
      duration: 0.5,
      ease: 'power2.in'
    });
  },

  async enter({ next }) {
    await gsap.fromTo(next.container,
      {
        opacity: 0,
        scale: 1.2
      },
      {
        opacity: 1,
        scale: 1,
        duration: 0.6,
        ease: 'power2.out'
      }
    );
  }
}

Rotate Zoom

3D rotation with zoom:

{
  name: 'rotate-zoom',

  async leave({ current }) {
    await gsap.to(current.container, {
      opacity: 0,
      scale: 0.9,
      rotationY: 15,
      duration: 0.6,
      ease: 'power2.in'
    });
  },

  async enter({ next }) {
    await gsap.fromTo(next.container,
      {
        opacity: 0,
        scale: 0.9,
        rotationY: -15
      },
      {
        opacity: 1,
        scale: 1,
        rotationY: 0,
        duration: 0.7,
        ease: 'power2.out'
      }
    );
  }
}

CSS Required:

[data-barba="wrapper"] {
  perspective: 1000px;
}

Creative Transitions

Curtain Effect

Animated overlay curtain:

{
  name: 'curtain',

  async leave({ current }) {
    const curtain = document.querySelector('.transition-curtain');

    // Bring curtain down
    await gsap.fromTo(curtain,
      { yPercent: -100 },
      {
        yPercent: 0,
        duration: 0.6,
        ease: 'power2.inOut'
      }
    );
  },

  async enter({ next }) {
    const curtain = document.querySelector('.transition-curtain');

    // Lift curtain up
    await gsap.to(curtain, {
      yPercent: 100,
      duration: 0.6,
      ease: 'power2.inOut'
    });
  }
}

HTML Required:

<div class="transition-curtain"></div>

CSS Required:

.transition-curtain {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  z-index: 9999;
  pointer-events: none;
  transform: translateY(-100%);
}

Wipe Effect

Diagonal wipe transition:

{
  name: 'wipe',

  async leave({ current }) {
    const wipe = document.querySelector('.transition-wipe');

    await gsap.fromTo(wipe,
      {
        xPercent: -100,
        skewX: -10
      },
      {
        xPercent: 0,
        skewX: 0,
        duration: 0.8,
        ease: 'power2.inOut'
      }
    );
  },

  async enter({ next }) {
    const wipe = document.querySelector('.transition-wipe');

    gsap.set(next.container, { opacity: 1 });

    await gsap.to(wipe, {
      xPercent: 100,
      skewX: 10,
      duration: 0.8,
      ease: 'power2.inOut'
    });
  }
}

HTML Required:

<div class="transition-wipe"></div>

CSS Required:

.transition-wipe {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #000;
  z-index: 9999;
  pointer-events: none;
  transform: translateX(-100%);
}

Staggered Elements

Elements animate out/in individually:

{
  name: 'stagger',

  async leave({ current }) {
    const tl = gsap.timeline();

    tl.to(current.container.querySelectorAll('.stagger-item'), {
      y: -50,
      opacity: 0,
      duration: 0.5,
      stagger: 0.05,
      ease: 'power2.in'
    })
    .to(current.container, {
      opacity: 0,
      duration: 0.3
    }, '-=0.2');

    await tl.play();
  },

  async enter({ next }) {
    const tl = gsap.timeline();

    gsap.set(next.container.querySelectorAll('.stagger-item'), {
      y: 50,
      opacity: 0
    });

    tl.to(next.container.querySelectorAll('.stagger-item'), {
      y: 0,
      opacity: 1,
      duration: 0.6,
      stagger: 0.05,
      ease: 'power2.out'
    });

    await tl.play();
  }
}

HTML Classes Required:

<div data-barba="container">
  <h1 class="stagger-item">Title</h1>
  <p class="stagger-item">Paragraph 1</p>
  <p class="stagger-item">Paragraph 2</p>
  <div class="stagger-item">Content</div>
</div>

Conditional Transitions

Different Transition Per Namespace

barba.init({
  transitions: [
    // From home: fade
    {
      name: 'from-home',
      from: { namespace: 'home' },

      async leave({ current }) {
        await gsap.to(current.container, {
          opacity: 0,
          duration: 0.5
        });
      },

      async enter({ next }) {
        await gsap.from(next.container, {
          opacity: 0,
          duration: 0.5
        });
      }
    },

    // To/from product: slide
    {
      name: 'product-transition',
      from: { namespace: 'product' },
      to: { namespace: 'product' },
      sync: true,

      leave({ current }) {
        return gsap.to(current.container, {
          x: '-100%',
          duration: 0.6
        });
      },

      enter({ next }) {
        gsap.set(next.container, { x: '100%' });
        return gsap.to(next.container, {
          x: '0%',
          duration: 0.6
        });
      }
    },

    // Default: crossfade
    {
      name: 'default',
      sync: true,

      leave({ current }) {
        return gsap.to(current.container, {
          opacity: 0,
          duration: 0.4
        });
      },

      enter({ next }) {
        return gsap.from(next.container, {
          opacity: 0,
          duration: 0.4
        });
      }
    }
  ]
});

Custom Rule Based on Data Attribute

{
  name: 'article-to-article',
  custom: ({ current, next }) => {
    // Check if both pages have data-article attribute
    return current.container.dataset.article && next.container.dataset.article;
  },

  async leave({ current }) {
    await gsap.to(current.container, {
      opacity: 0,
      scale: 0.95,
      duration: 0.3
    });
  },

  async enter({ next }) {
    await gsap.fromTo(next.container,
      { opacity: 0, scale: 1.05 },
      { opacity: 1, scale: 1, duration: 0.4 }
    );
  }
}

Production Examples

E-commerce Product Pages

Fast transitions between products, slower elsewhere:

barba.init({
  transitions: [
    // Product to product: fast slide
    {
      name: 'product-to-product',
      from: { namespace: 'product' },
      to: { namespace: 'product' },
      sync: true,

      leave({ current }) {
        return gsap.to(current.container, {
          x: '-50%',
          opacity: 0,
          duration: 0.4,
          ease: 'power2.inOut'
        });
      },

      enter({ next }) {
        gsap.set(next.container, { x: '50%', opacity: 0 });

        return gsap.to(next.container, {
          x: '0%',
          opacity: 1,
          duration: 0.4,
          ease: 'power2.inOut'
        });
      }
    },

    // Default: elegant fade
    {
      name: 'default',

      async leave({ current }) {
        await gsap.to(current.container, {
          opacity: 0,
          y: -30,
          duration: 0.6,
          ease: 'power2.in'
        });
      },

      async enter({ next }) {
        await gsap.fromTo(next.container,
          { opacity: 0, y: 30 },
          { opacity: 1, y: 0, duration: 0.7, ease: 'power2.out' }
        );
      }
    }
  ]
});

Portfolio with Loading Indicator

barba.init({
  transitions: [{
    name: 'portfolio',

    async leave({ current }) {
      const loader = document.querySelector('.page-loader');

      // Fade out content
      await gsap.to(current.container, {
        opacity: 0,
        duration: 0.4
      });

      // Show loader
      gsap.to(loader, {
        opacity: 1,
        duration: 0.3
      });
    },

    async enter({ next }) {
      const loader = document.querySelector('.page-loader');

      // Hide loader
      await gsap.to(loader, {
        opacity: 0,
        duration: 0.3
      });

      // Fade in content
      await gsap.from(next.container, {
        opacity: 0,
        duration: 0.5
      });
    }
  }]
});

HTML:

<div class="page-loader">Loading...</div>

CSS:

.page-loader {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 1.5rem;
  opacity: 0;
  z-index: 9998;
  pointer-events: none;
}

Blog with Staggered Content

barba.init({
  transitions: [{
    name: 'blog',

    async leave({ current }) {
      const tl = gsap.timeline();

      tl.to(current.container.querySelector('.post-header'), {
        y: -50,
        opacity: 0,
        duration: 0.4
      })
      .to(current.container.querySelectorAll('.post-content > *'), {
        y: -30,
        opacity: 0,
        duration: 0.3,
        stagger: 0.03
      }, '-=0.3')
      .to(current.container, {
        opacity: 0,
        duration: 0.2
      });

      await tl.play();
    },

    async enter({ next }) {
      const tl = gsap.timeline();

      gsap.set(next.container.querySelector('.post-header'), {
        y: 50,
        opacity: 0
      });
      gsap.set(next.container.querySelectorAll('.post-content > *'), {
        y: 30,
        opacity: 0
      });

      tl.to(next.container.querySelector('.post-header'), {
        y: 0,
        opacity: 1,
        duration: 0.6,
        ease: 'power3.out'
      })
      .to(next.container.querySelectorAll('.post-content > *'), {
        y: 0,
        opacity: 1,
        duration: 0.5,
        stagger: 0.05,
        ease: 'power2.out'
      }, '-=0.4');

      await tl.play();
    }
  }]
});

Agency Site with Parallax Layers

barba.init({
  transitions: [{
    name: 'parallax',
    sync: true,

    async leave({ current }) {
      const tl = gsap.timeline();

      // Parallax effect - different speeds
      tl.to(current.container.querySelector('.layer-bg'), {
        y: -50,
        opacity: 0,
        duration: 0.8
      }, 0)
      .to(current.container.querySelector('.layer-mid'), {
        y: -100,
        opacity: 0,
        duration: 0.8
      }, 0)
      .to(current.container.querySelector('.layer-front'), {
        y: -150,
        opacity: 0,
        duration: 0.8
      }, 0);

      await tl.play();
    },

    async enter({ next }) {
      const tl = gsap.timeline();

      gsap.set(next.container.querySelectorAll('[class^="layer-"]'), {
        opacity: 0
      });

      tl.from(next.container.querySelector('.layer-bg'), {
        y: 50,
        opacity: 0,
        duration: 0.8
      }, 0)
      .from(next.container.querySelector('.layer-mid'), {
        y: 100,
        opacity: 0,
        duration: 0.8
      }, 0)
      .from(next.container.querySelector('.layer-front'), {
        y: 150,
        opacity: 0,
        duration: 0.8
      }, 0);

      await tl.play();
    }
  }]
});

SaaS Dashboard with Minimal Transition

Fast, subtle transitions for app-like feel:

barba.init({
  transitions: [{
    name: 'dashboard',

    async leave({ current }) {
      await gsap.to(current.container, {
        opacity: 0,
        duration: 0.2,
        ease: 'power1.inOut'
      });
    },

    async enter({ next }) {
      gsap.set(next.container, { opacity: 0 });

      await gsap.to(next.container, {
        opacity: 1,
        duration: 0.2,
        ease: 'power1.inOut'
      });
    }
  }]
});

Complete Starter Template

Full implementation with multiple transitions:

import barba from '@barba/core';
import gsap from 'gsap';

barba.init({
  transitions: [
    // Initial page load
    {
      name: 'initial-load',
      once: async ({ next }) => {
        const loader = document.querySelector('.page-loader');

        await gsap.to(loader, {
          opacity: 0,
          duration: 0.5,
          delay: 0.5
        });

        gsap.set(loader, { display: 'none' });

        await gsap.from(next.container, {
          opacity: 0,
          y: 50,
          duration: 0.8,
          ease: 'power2.out'
        });
      }
    },

    // Same namespace: fast transition
    {
      name: 'same-namespace',
      custom: ({ current, next }) => current.namespace === next.namespace,

      async leave({ current }) {
        await gsap.to(current.container, {
          opacity: 0,
          duration: 0.3
        });
      },

      async enter({ next }) {
        await gsap.from(next.container, {
          opacity: 0,
          duration: 0.3
        });
      }
    },

    // Default: elegant fade
    {
      name: 'default',

      async leave({ current }) {
        await gsap.to(current.container, {
          opacity: 0,
          y: -30,
          duration: 0.5,
          ease: 'power2.in'
        });
      },

      async enter({ next }) {
        await gsap.fromTo(next.container,
          { opacity: 0, y: 30 },
          { opacity: 1, y: 0, duration: 0.6, ease: 'power2.out' }
        );
      }
    }
  ]
});

// Global hooks
barba.hooks.beforeEnter(() => {
  window.scrollTo(0, 0);
});

barba.hooks.after(({ next }) => {
  // Analytics
  if (typeof gtag !== 'undefined') {
    gtag('config', 'GA_MEASUREMENT_ID', {
      page_path: next.url.path
    });
  }

  // Re-initialize scripts
  if (typeof Prism !== 'undefined') {
    Prism.highlightAll();
  }
});

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides documentation and tools for implementing page transitions using the Barba.js library. It includes helpful guides and two Python scripts: one for generating animation code snippets and another for setting up a new project. The project setup script automates the installation of standard, well-known development dependencies like GSAP and Vite through npm, which is a common practice for web development tools.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    8 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 1da73fe. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 11 months ago

README badge

README badge for freshtechbro/claudedesignskills/barba-js