Folio iteration
0123456789
0123456789
Lab
Scroll0px
Velocity0
Direction
Progress0%
Version: 1.0.0

Interactions & animations Lab

Nuxt3.x
Vue3.5
TypeScript5.x
GSAP3.x
Lenis1.x

Explore scroll-based animations, GSAP effects, and custom components built with Nuxt 3 and TypeScript

0%Progress
In View
This text fades in based on scroll progress

Scroll Progress

Track scroll progress of any element from 0% to 100% as it moves through the viewport.

Usage

const element = ref();

const { progress, isInView } = useScrollProgress({
  target: element,
  offset: [0, 0]
});

Options

  • target - Element to track
  • offset - [start, end] offsets in pixels
  • onProgress - Callback function
Slow
Medium
Fast

Parallax Effect

Elements move at different speeds based on scroll position. The dotted line shows the reference position.

Implementation

const { progress } = useScrollProgress({
  target: container,
  offset: [-200, 200]
});

// Different speeds for each layer
const offset1 = computed(() =>
  (progress.value - 0.5) * -100
);
const offset2 = computed(() =>
  (progress.value - 0.5) * -200
);
const offset3 = computed(() =>
  (progress.value - 0.5) * -300
);

Tips

  • Use negative multipliers for upward movement
  • Larger values = faster movement
  • Center at 0.5 (50% progress) for balanced effect
👀

Scroll to view this section

Intersection Observer

Detect when elements enter or leave the viewport. Notice how this section's background color changes.

Usage

const element = ref();
const { isInView } = useScrollProgress({
  target: element
});

// CSS based on state
<section :data-in-view="isInView">
  ...
</section>

CSS Example

.section {
  background: #f5f5f5;
  transition: background 0.6s ease;
}

.section[data-in-view="true"] {
  background: #fb6464;
}
1
2
3
4
5
6

GSAP Scroll Animations

Animate elements based on scroll position using GSAP and scroll progress tracking.

Implementation

const boxes = ref([]);

onMounted(() => {
  // Set initial state
  gsap.set(boxes.value, {
    opacity: 0,
    y: 100,
    rotation: 90
  });

  // Watch scroll
  const { watch } = useScroll();
  watch(() => {
    boxes.value.forEach(box => {
      const rect = box.getBoundingClientRect();
      const progress = calculateProgress(rect);

      gsap.to(box, {
        opacity: progress,
        y: (1 - progress) * 100,
        rotation: (1 - progress) * 90
      });
    });
  });
});
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Text Reveal

Characters gradually become visible as you scroll, creating a reveal effect.

Usage

const element = ref();

useTextReveal(element, {
  fromColor: 'rgba(0, 0, 0, 0.15)',
  toColor: 'rgba(0, 0, 0, 1)'
});

How it Works

  • Splits text into individual characters
  • Animates color based on scroll progress
  • Starts when element enters viewport
  • Completes when element reaches center
Random character reveal animation

Code Reveal

Characters randomly reveal with instant opacity changes, creating a glitch-like code reveal effect.

Basic Usage

const element = ref();

const { startAnimation, reset, splitText } = useCodeReveal(element, {
  duration: 0.3,
  delay: 0,
  revealPercentage: 1
});

// Split text first
onMounted(async () => {
  await splitText();
});

// Trigger animation
startAnimation();

Options

  • duration - Animation duration in seconds (default: 1.2)
  • delay - Delay before animation starts in seconds (default: 0)
  • randomChars - Characters used during reveal (default: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%&*")
  • revealPercentage - Percentage of chars to reveal per frame (default: 0.15)

How it Works

  • Uses GSAP SplitText to split text into characters
  • Randomly reveals characters using requestAnimationFrame
  • Frame-based timing ensures predictable duration
  • Instant opacity change (no CSS transition)
  • Each character appears exactly once

Scroll-Triggered Example

// Split text on mount to hide it
onMounted(async () => {
  await splitText();
});

// Watch for trigger condition
watch(
  () => uiStore.pixelTransitionComplete,
  async (isComplete) => {
    if (isComplete) {
      startAnimation();
    }
  }
);

Animate by words

Character by character

Scroll triggered animation

Scroll to animate

Split Text Animation

Animate text by splitting it into words, characters, or lines with stagger effects.

Manual Control

const element = ref();
const { animate, isAnimated } = useSplitText(element, {
  type: 'words', // or 'chars', 'lines'
  stagger: 0.08,
  duration: 0.6
});

// Toggle animation
animate(!isAnimated.value);

Auto on Scroll

useSplitText(element, {
  type: 'words',
  animateOnScroll: true,
  scrollOffset: [150, -100]
});

Glitch Effect

Hover effect that randomly reveals characters with special symbols, creating a glitch aesthetic.

Usage

// Basic
<a v-glitch>Hover Me</a>

// Custom color
<a v-glitch="{ color: '#FFCC00' }">
  Orange Glitch
</a>

// Custom speed (ms)
<a v-glitch="{ interval: 100 }">
  Slow
</a>

Features

  • Random special characters
  • Non-sequential reveal order
  • Fixed width (no layout shift)
  • Single execution per hover
Box 1
Box 2
Box 3

Scroll Reveal Directive

Directive that automatically animates elements when they enter the viewport.

Basic Usage

<div v-scroll-reveal>
  Fade in on scroll
</div>

With Options

<div v-scroll-reveal="{
  delay: 0.2,
  duration: 1
}">
  Delayed reveal
</div>

<!-- Stagger children -->
<div v-scroll-reveal="{
  staggerChildren: true,
  stagger: 0.15
}">
  <div>Child 1</div>
  <div>Child 2</div>
  <div>Child 3</div>
</div>
Gradient background
Move your cursor here to see pixel trail

Pixel Trail

WebGL-powered pixel trail effect that captures image colors and creates a scattered, randomized trail following mouse movement.

Usage

<PixelTrail
  targetSelector=".your-image"
  containerSelector=".your-container"
  captureMode="all"
/>

Props

  • targetSelector - CSS selector for images to capture (default: ".block-project-bg__image img")
  • containerSelector - Container to constrain pixel trail (optional)
  • captureMode - "all" captures all visible images, "centered" captures only the centered image (default: "all")

Features

  • WebGL-based rendering for optimal performance
  • Captures colors from underlying images
  • Random scattered pixel appearance
  • Individual pixel lifetimes for organic disappearance
  • Automatic color lightening for visibility
  • No transparency - solid pixel blocks

Click the button to see the pixel reveal animation.
This effect is used on page load throughout the site.

Pixel Transition

Full-screen pixel reveal animation used for page transitions. Creates a pixelated reveal effect with staggered timing.

Usage

<PixelTransition
  ref="pixelTransition"
  @transitionComplete="handleComplete"
/>

// Trigger the transition
const pixelTransition = ref();
pixelTransition.value?.startTransition();

Events

  • @transitionComplete - Emitted when animation finishes

How it Works

  • Divides screen into pixel grid
  • Each pixel has randomized delay for staggered reveal
  • Canvas-based rendering for performance
  • Automatically triggers on page load
  • Coordinates with UI store for animation timing

Integration Example

// In app.vue
const pixelTransition = ref();
const uiStore = useUIStore();

const handlePixelTransitionComplete = () => {
  uiStore.setPixelTransitionComplete(true);
};

// Trigger on loader hide
const handleLoaderHide = () => {
  nextTick(() => {
    pixelTransition.value?.startTransition();
  });
};
0123456789
0123456789

Rolling Number

Animated numbers with smooth rolling effect, like a slot machine. Each digit animates independently.

Usage

<RollingNumber
  :from="0"
  :to="42"
  :digits="2"
  :duration="2"
  :stagger="0.1"
  ease="power2.inOut"
  @complete="onComplete"
/>

Props

  • from - Starting number (default: 0)
  • to - Target number (required)
  • digits - Number of digits to display (default: 2)
  • duration - Animation duration in seconds (default: 2)
  • stagger - Delay between each digit (default: 0.1)
  • ease - GSAP easing function (default: "power2.inOut")

Methods

const ref = ref();
ref.value.animateTo(99);
ref.value.reset(0);

Swiper Component

GSAP-powered horizontal carousel with multiple configurations

Basic Loop with Navigation

Simple infinite loop carousel with prev/next buttons

1
3
4
5
6
7
8

Centered Slides

Active slide is centered in the viewport

1
3
4
5
6

Autoplay

Automatically advances every 3 seconds

1
3
4
5

No Loop (Finite)

Stops at first and last slide

1
3
4
5
6
7
Hover Me

Mouse Follower

Custom mouse cursor with button integration via UI store.

Usage

const uiStore = useUIStore();

// Show button
const show = () => {
  uiStore.showMouseFollower(true, true);
};

// Hide button
const hide = () => {
  uiStore.hideMouseFollower();
};

In Template

<div
  @mouseenter="show"
  @mouseleave="hide"
>
  Hover to show button
</div>