Interactions & animations Lab
Explore scroll-based animations, GSAP effects, and custom components built with Nuxt 3 and TypeScript
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 trackoffset- [start, end] offsets in pixelsonProgress- Callback function
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;
}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
});
});
});
});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
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
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>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();
});
};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
Centered Slides
Active slide is centered in the viewport
Autoplay
Automatically advances every 3 seconds
No Loop (Finite)
Stops at first and last slide
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>