CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-scrollama

Lightweight scrollytelling library using IntersectionObserver for scroll-driven interactive narratives

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Scrollama

Scrollama is a lightweight JavaScript library for creating scrollytelling (scroll-driven storytelling) experiences using the IntersectionObserver API. It provides a simple interface for detecting when elements enter or exit the viewport during scrolling, with support for step-based interactions, progress tracking, custom offsets, and sticky graphic implementations.

Package Information

  • Package Name: scrollama
  • Package Type: npm
  • Language: JavaScript (with TypeScript definitions)
  • Installation: npm install scrollama

Core Imports

import scrollama from "scrollama";

For CommonJS:

const scrollama = require("scrollama");

Browser (CDN):

<script src="https://unpkg.com/scrollama"></script>

Basic Usage

import scrollama from "scrollama";

// Create scrollama instance
const scroller = scrollama();

// Setup with step elements and callbacks
scroller
  .setup({
    step: ".step", // required: CSS selector for step elements
    offset: 0.5,   // trigger when element is 50% in viewport
    debug: false   // optional visual debugging
  })
  .onStepEnter((response) => {
    // Fired when step enters offset threshold
    const { element, index, direction } = response;
    console.log("Step entered:", index, direction);
  })
  .onStepExit((response) => {
    // Fired when step exits offset threshold  
    const { element, index, direction } = response;
    console.log("Step exited:", index, direction);
  });

Architecture

Scrollama uses the IntersectionObserver API for performance optimization over traditional scroll events. Key components:

  • Factory Function: scrollama() creates instances with chainable method calls
  • Observer Management: Automatically manages IntersectionObserver instances per step
  • Resize Handling: Built-in ResizeObserver automatically handles viewport changes
  • Progress Tracking: Optional fine-grained progress monitoring within steps
  • Debug Mode: Visual overlays for development and testing

Capabilities

Instance Creation

Creates a new scrollama instance for managing scroll-driven interactions.

/**
 * Creates a new scrollama instance
 * @returns ScrollamaInstance - Instance with chainable configuration methods
 */
function scrollama(): ScrollamaInstance;

Setup Configuration

Configures the scrollama instance with step elements and interaction settings.

/**
 * Configure scrollama instance with steps and options
 * @param options - Configuration object
 * @returns ScrollamaInstance - For method chaining
 */
setup(options: ScrollamaOptions): ScrollamaInstance;

interface ScrollamaOptions {
  /** Required: CSS selector, NodeList, HTMLElement[], or single HTMLElement for step elements */
  step: string | NodeList | HTMLElement[] | HTMLElement;
  /** Trigger position in viewport: 0-1 or string with "px" (default: 0.5) */
  offset?: number | string;
  /** Enable incremental progress updates (default: false) */
  progress?: boolean;
  /** Granularity of progress updates in pixels, minimum 1 (default: 4) */
  threshold?: number;
  /** Only trigger steps once, then remove listeners (default: false) */
  once?: boolean;
  /** Show visual debugging overlays (default: false) */
  debug?: boolean;
  /** Parent element for step selector, useful for shadow DOM */
  parent?: HTMLElement;
  /** Parent element for scroll story, for overflow: scroll/auto containers */
  container?: HTMLElement;
  /** Element used as viewport for visibility checking (default: browser viewport) */
  root?: HTMLElement;
}

Usage Example:

// Basic setup
scroller.setup({
  step: ".story-step"
});

// Advanced setup with progress tracking
scroller.setup({
  step: ".story-step",
  offset: 0.8,        // Trigger at 80% viewport height
  progress: true,     // Enable progress callbacks
  threshold: 2,       // Higher granularity
  debug: true,        // Show debug overlays
  container: document.querySelector('.scroll-container')
});

Step Event Callbacks

Register callbacks for step enter and exit events.

/**
 * Callback fired when step elements enter the offset threshold
 * @param callback - Function receiving step event data
 * @returns ScrollamaInstance - For method chaining
 */
onStepEnter(callback: (response: CallbackResponse) => void): ScrollamaInstance;

/**
 * Callback fired when step elements exit the offset threshold
 * @param callback - Function receiving step event data
 * @returns ScrollamaInstance - For method chaining
 */
onStepExit(callback: (response: CallbackResponse) => void): ScrollamaInstance;

interface CallbackResponse {
  /** The DOM element that triggered the event */
  element: HTMLElement;
  /** Zero-based index of the step element */
  index: number;
  /** Scroll direction when event fired */
  direction: "up" | "down";
}

Usage Example:

scroller
  .onStepEnter((response) => {
    const { element, index, direction } = response;
    element.classList.add('is-active');
    
    // Handle different steps
    if (index === 0) {
      // First step logic
    } else if (index === 2) {
      // Third step logic
    }
  })
  .onStepExit((response) => {
    const { element, index, direction } = response;
    element.classList.remove('is-active');
  });

Progress Tracking

Monitor fine-grained progress within step elements (requires progress: true in setup).

/**
 * Callback fired for incremental progress through steps
 * @param callback - Function receiving progress event data
 * @returns ScrollamaInstance - For method chaining
 */
onStepProgress(callback: (response: ProgressCallbackResponse) => void): ScrollamaInstance;

interface ProgressCallbackResponse {
  /** The DOM element being tracked */
  element: HTMLElement;
  /** Zero-based index of the step element */
  index: number;
  /** Progress through the step (0.0 to 1.0) */
  progress: number;
  /** Current scroll direction */
  direction: "up" | "down";
}

Usage Example:

scroller
  .setup({
    step: ".step",
    progress: true,
    threshold: 1  // Very granular updates
  })
  .onStepProgress((response) => {
    const { element, index, progress, direction } = response;
    
    // Update progress bar
    const progressBar = element.querySelector('.progress-bar');
    progressBar.style.width = `${progress * 100}%`;
    
    // Fade in/out based on progress
    element.style.opacity = progress;
  });

Offset Management

Get or set the trigger offset position dynamically.

/**
 * Get or set the offset trigger value (note: method name is 'offset' in implementation)
 * @param value - Optional new offset value (0-1 or string with "px")
 * @returns ScrollamaInstance if setting, current offset value if getting
 */
offset(value?: number | string): ScrollamaInstance | number;

Usage Example:

// Get current offset
const currentOffset = scroller.offset();

// Set new offset
scroller.offset(0.25); // Trigger at 25% viewport height
scroller.offset("100px"); // Trigger at 100px from top

Instance Control

Control scrollama instance state and lifecycle.

/**
 * Resume observing for trigger changes (if previously disabled)
 * @returns ScrollamaInstance - For method chaining
 */
enable(): ScrollamaInstance;

/**
 * Stop observing for trigger changes
 * @returns ScrollamaInstance - For method chaining
 */
disable(): ScrollamaInstance;

/**
 * Manual resize trigger (automatic with built-in ResizeObserver)
 * @returns ScrollamaInstance - For method chaining
 */
resize(): ScrollamaInstance;

/**
 * Remove all observers and callback functions
 * @returns void
 */
destroy(): void;

Usage Example:

// Temporarily disable
scroller.disable();

// Re-enable later
scroller.enable();

// Clean up when done
scroller.destroy();

Custom Offset Data Attributes

Override the global offset for individual step elements using data attributes.

<!-- Use percentage (0-1) -->
<div class="step" data-offset="0.25">Step with 25% offset</div>

<!-- Use pixels -->
<div class="step" data-offset="100px">Step with 100px offset</div>

<!-- Use default global offset -->
<div class="step">Step with global offset</div>

Types

Complete TypeScript type definitions for all interfaces and callbacks.

interface ScrollamaInstance {
  setup(options: ScrollamaOptions): ScrollamaInstance;
  onStepEnter(callback: StepCallback): ScrollamaInstance;
  onStepExit(callback: StepCallback): ScrollamaInstance;
  onStepProgress(callback: StepProgressCallback): ScrollamaInstance;
  offset(value?: number | string): ScrollamaInstance | number;
  resize(): ScrollamaInstance;
  enable(): ScrollamaInstance;
  disable(): ScrollamaInstance;
  destroy(): void;
}

type DecimalType = 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1;

type StepCallback = (response: CallbackResponse) => void;
type StepProgressCallback = (response: ProgressCallbackResponse) => void;

Common Patterns

Sticky Graphic Side-by-Side

<div class="container">
  <div class="graphic">
    <!-- Fixed graphic content -->
  </div>
  <div class="scroller">
    <div class="step" data-step="1">First step content</div>
    <div class="step" data-step="2">Second step content</div>
    <div class="step" data-step="3">Third step content</div>
  </div>
</div>
.container {
  display: flex;
}

.graphic {
  position: sticky;
  top: 0;
  flex: 1;
  height: 100vh;
}

.scroller {
  flex: 1;
}

.step {
  margin-bottom: 80vh;
  padding: 1rem;
}

Mobile-Friendly Pixel Offsets

// Use pixel offsets for consistent mobile behavior
const isMobile = window.innerWidth < 768;
const offset = isMobile ? "150px" : 0.5;

scroller.setup({
  step: ".step",
  offset: offset
});

Dynamic Step Management

// Add new steps dynamically
function addStep(content) {
  const newStep = document.createElement('div');
  newStep.className = 'step';
  newStep.textContent = content;
  document.querySelector('.scroller').appendChild(newStep);
  
  // Reconfigure scrollama
  scroller.setup({
    step: ".step" // Automatically picks up new steps
  });
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/scrollama@3.2.x
Publish Source
CLI
Badge
tessl/npm-scrollama badge