npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-scroll-narrator

v1.0.5

Published

A React component for creating scroll-driven storytelling UIs with smooth animations, inspired by Apple product pages

Downloads

9

Readme

React Scroll Narrator

npm version License: MIT TypeScript

A powerful React component for creating Apple-style scroll-driven storytelling experiences with smooth animations, parallax effects, and interactive navigation.

📺 Demo

React Scroll Narrator Demo

🚀 What's New

  • Programmatic Navigation: Direct API access with scrollToStep() method
  • Enhanced Progress Indicators: Click to navigate functionality
  • Improved Performance: Dual detection system with scroll listeners and IntersectionObserver
  • Better Animation Triggers: Content appears immediately when sections become active
  • Full Viewport Sections: Each NarrationStep takes full screen height (100vh)

✨ Features

  • 🎭 Multiple Animation Types: Fade, slide, scale, reveal, parallax, and custom animations
  • 📱 Touch & Mobile Optimized: Swipe gestures and touch navigation
  • ⌨️ Keyboard Navigation: Full keyboard support with arrow keys and number shortcuts
  • 🎨 Parallax Backgrounds: Smooth parallax scrolling effects
  • 📍 Progress Indicators: Interactive dots, bars, and minimal progress displays with click navigation
  • ♿ Accessibility Ready: Screen reader support and ARIA attributes
  • ⚡ High Performance: Optimized with IntersectionObserver API and scroll-based detection
  • 🔧 Fully Customizable: Extensive props for styling and behavior
  • 🎯 TypeScript Support: Complete type definitions included
  • 🎪 Programmatic Control: Direct API access for custom navigation and control

🚀 Installation

npm install react-scroll-narrator

Peer Dependencies

npm install react react-dom framer-motion clsx

📖 Quick Start

import { ScrollNarrator, NarrationStep, ProgressIndicator, ScrollNarratorRef } from "react-scroll-narrator";
import { useState, useRef } from "react";

export default function MyApp() {
  const [currentStep, setCurrentStep] = useState(0);
  const scrollNarratorRef = useRef<ScrollNarratorRef>(null);

  const handleStepClick = (stepIndex) => {
    scrollNarratorRef.current?.scrollToStep(stepIndex);
  };

  return (
    <div className="relative">
      {/* Progress Indicator */}
      <ProgressIndicator
        total={3}
        current={currentStep}
        style="dots"
        position="right"
        onStepClick={handleStepClick}
      />

      <ScrollNarrator
        ref={scrollNarratorRef}
        animation="fade"
        onStepChange={setCurrentStep}
        keyboardNavigation={true}
        touchNavigation={true}
      >
        <NarrationStep>
          <h1>Welcome to Scroll Narrator! 🚀</h1>
          <p>Your scroll-driven storytelling starts here.</p>
        </NarrationStep>

        <NarrationStep animation="slideUp">
          <div className="product-showcase">
            <img src="/product.png" alt="Amazing Product" />
            <h2>Incredible Features</h2>
            <p>Experience the magic of smooth scroll animations.</p>
          </div>
        </NarrationStep>

        <NarrationStep animation="reveal">
          <div className="cta-section">
            <h2>Get Started Today</h2>
            <button>Learn More</button>
          </div>
        </NarrationStep>
      </ScrollNarrator>
    </div>
  );
}

🎛️ API Reference

ScrollNarrator

The main container component that manages scroll behavior and step transitions.

const scrollNarratorRef = useRef<ScrollNarratorRef>(null);

// Programmatic navigation
scrollNarratorRef.current?.scrollToStep(2);

<ScrollNarrator
  ref={scrollNarratorRef}
  animation="fade"
  onStepChange={(index) => console.log(index)}
  keyboardNavigation={true}
  touchNavigation={true}
  parallax={true}
  parallaxSpeed={0.5}
  className="my-custom-class"
>
  {/* NarrationStep components */}
</ScrollNarrator>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | animation | AnimationType | "fade" | Default animation for all steps | | onStepChange | (index: number, stepId?: string) => void | - | Callback when step becomes active | | sticky | boolean | true | Whether steps are sticky scroll | | parallax | boolean | false | Enable parallax backgrounds | | parallaxSpeed | number | 0.5 | Parallax scroll speed multiplier | | keyboardNavigation | boolean | true | Enable keyboard navigation | | touchNavigation | boolean | true | Enable touch/swipe navigation | | className | string | - | Custom CSS class | | style | CSSProperties | - | Custom inline styles |

Ref Methods

| Method | Signature | Description | |--------|-----------|-------------| | scrollToStep | (stepIndex: number) => void | Programmatically scroll to a specific step |

TypeScript Types

import type {
  ScrollNarratorProps,
  NarrationStepProps,
  AnimationType,
  ProgressIndicatorProps,
  ScrollNarratorRef
} from "react-scroll-narrator";

NarrationStep

Individual step component that contains your content and handles animations.

<NarrationStep
  id="unique-step-id"
  animation="slideUp"
  backgroundImage="/hero-bg.jpg"
  backgroundColor="#000"
  className="custom-step-class"
>
  <h1>Your Content Here</h1>
</NarrationStep>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | id | string | auto | Unique step identifier | | animation | AnimationType | inherit | Override animation for this step | | backgroundImage | string | - | Background image URL | | backgroundColor | string | - | Background color | | className | string | - | Custom CSS class | | style | CSSProperties | - | Custom inline styles |

ProgressIndicator

Visual indicator showing current progress through the narrative.

<ProgressIndicator
  total={5}
  current={2}
  style="dots"
  position="right"
  onStepClick={(index) => console.log(index)}
  size="lg"
  showNumbers={true}
/>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | total | number | - | Total number of steps | | current | number | - | Current active step index | | style | "dots" \| "bar" \| "minimal" | "dots" | Indicator style | | position | "top" \| "bottom" \| "left" \| "right" | "right" | Position on screen | | onStepClick | (index: number) => void | - | Click handler for navigation | | showNumbers | boolean | false | Show step numbers | | size | "sm" \| "md" \| "lg" | "md" | Indicator size | | className | string | - | Custom CSS class |

🎨 Animation Types

Choose from these built-in animation types:

  • "fade" - Simple opacity transition
  • "slide" - Slide in from right
  • "slideUp" - Slide up from bottom
  • "slideDown" - Slide down from top
  • "slideLeft" - Slide in from right
  • "slideRight" - Slide in from left
  • "scale" - Scale in with opacity
  • "scaleFade" - Gentle scale and fade
  • "reveal" - Clip-path reveal effect
  • "parallax" - Subtle parallax movement
  • "none" - No animation

🎯 Advanced Examples

With Progress Indicator

import { ScrollNarrator, NarrationStep, ProgressIndicator, ScrollNarratorRef } from "react-scroll-narrator";
import { useState, useRef } from "react";

function App() {
  const [currentStep, setCurrentStep] = useState(0);
  const scrollNarratorRef = useRef<ScrollNarratorRef>(null);

  const handleStepClick = (stepIndex: number) => {
    scrollNarratorRef.current?.scrollToStep(stepIndex);
  };

  return (
    <div className="relative">
      <ProgressIndicator
        total={3}
        current={currentStep}
        style="dots"
        position="right"
        onStepClick={handleStepClick}
        size="lg"
      />

      <ScrollNarrator
        ref={scrollNarratorRef}
        onStepChange={setCurrentStep}
        keyboardNavigation={true}
        touchNavigation={true}
      >
        <NarrationStep>
          <h1>Step 1</h1>
          <p>Scroll or click the dots to navigate</p>
        </NarrationStep>

        <NarrationStep animation="slideUp">
          <h1>Step 2</h1>
          <p>Smooth animations and interactions</p>
        </NarrationStep>

        <NarrationStep animation="reveal">
          <h1>Step 3</h1>
          <p>Beautiful storytelling experiences</p>
        </NarrationStep>
      </ScrollNarrator>
    </div>
  );
}

With Parallax Backgrounds

<ScrollNarrator
  height="100vh"
  parallax={true}
  parallaxSpeed={0.3}
>
  <NarrationStep backgroundImage="/mountain-bg.jpg">
    <h1>Mountain View</h1>
  </NarrationStep>

  <NarrationStep backgroundImage="/ocean-bg.jpg">
    <h1>Ocean Scene</h1>
  </NarrationStep>
</ScrollNarrator>

Custom Animations with Framer Motion

import { motion } from "framer-motion";

<NarrationStep animation="none">
  <motion.div
    initial={{ x: -100, opacity: 0 }}
    animate={{ x: 0, opacity: 1 }}
    transition={{ duration: 0.8, ease: "easeOut" }}
  >
    <h1>Custom Animation</h1>
  </motion.div>
</NarrationStep>

🎮 Controls

Keyboard Navigation

  • ↑/↓ or Page Up/Down - Navigate between steps
  • Home/End - Jump to first/last step
  • 1-9 - Jump to specific step number

Touch Navigation

  • Swipe Up/Down - Navigate between steps on mobile devices
  • Touch optimized for smooth scrolling experience

🎨 Styling

The component comes with minimal default styles. You can customize everything with CSS:

/* Custom step styles */
.narration-step {
  /* Your custom styles */
}

/* Container styles */
.scroll-narrator-container {
  /* Container modifications */
}

/* Progress indicator customization */
.progress-indicator {
  /* Custom progress styles */
}

🔧 TypeScript Support

Full TypeScript support with complete type definitions:

import type {
  ScrollNarratorProps,
  NarrationStepProps,
  AnimationType,
  ProgressIndicatorProps
} from "react-scroll-narrator";

🌟 Use Cases

  • Product Showcases - Apple-style product reveals
  • Storytelling Websites - Long-form narratives with smooth transitions
  • Portfolio Sites - Creative showcases with scroll interactions
  • Marketing Landing Pages - Engaging user experiences
  • Interactive Presentations - Scroll-based slide decks
  • Brand Stories - Cinematic storytelling experiences

📱 Browser Support

  • Chrome 58+
  • Firefox 55+
  • Safari 11+
  • Edge 79+
  • iOS Safari 11+
  • Android Chrome 58+

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments


Made with ❤️ for creating beautiful scroll experiences