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 🙏

© 2025 – Pkg Stats / Ryan Hefner

slow-scroll

v0.0.7

Published

Super Slow Smooth Scroll

Readme

Super Slow Smooth Scroll

Enables smooth and slow scrolling across all browsers.

View Demo

How It Works

Time:    0ms          16ms         33ms         50ms         66ms (next scroll)
         │            │            │            │            │
Scroll:  scrollBy(1px)                                       scrollBy(1px)
         │            │            │            │            │
Visual:  translate(0) (-0.25px)    (-0.5px)     (-0.75px)    translate(0)
         │            │            │            │            │
Result:  [------------- Appears smooth at 60fps -------------]

The target element uses translateY to visually interpolate between actual scroll updates, appearing smooth at the device's native refresh rate.

Installation

npm

npm install slow-scroll
import createSlowScroll from "slow-scroll";

const scroller = SlowScroll.createSlowScroll({
  target: "#container",
  speed: 30,
  bounce: true,
});

CDN

<!-- Load from CDN -->
<script src="https://unpkg.com/slow-scroll@latest/dist/slow-scroll.umd.js"></script>

<script>
  const scroller = SlowScroll.createSlowScroll({
    target: "#container",
    speed: 30,
    bounce: true,
  });
</script>

Note: When using the CDN version, the library is available as SlowScroll global variable.

Usage

Basic Example

// Simplest usage - scrolls body automatically
const scroller = createSlowScroll();

// With custom options
const scroller = createSlowScroll({
  target: ".content", // Scrollable container (defaults to 'body')
  interpolationTarget: ".inner", // Element to apply interpolation (optional, defaults to target)
  speed: 30, // Pixels per second - positive = down/right, negative = up/left (default: 30)
  interpolation: true, // Enable interpolation (default: true)
  bounce: false, // Reverse at boundaries (default: false)
  isHorizontal: false, // Scroll horizontally instead of vertically (default: false)
  autoplay: true, // Start automatically (default: true)
});

// Stop scrolling when needed
scroller.stop();

// Restart if stopped
scroller.start();

Recommended speed: 15-30 px/s for best balance between smoothness and performance.

Separate Interpolation Target

By default, interpolation transforms are applied to the scrollable element itself. However, in complex layouts with fixed headers, sidebars, or other non-scrolling elements, you may notice unwanted visual jitter or stutter on those elements.

Use interpolationTarget to apply the smooth interpolation only to the content area, preventing unwanted transform effects on other parts of your layout:

const scroller = createSlowScroll({
  target: ".scrollable-container", // Element with overflow: auto
  interpolationTarget: ".inner-content", // Only this element gets the smooth interpolation
  speed: 20,
  interpolation: true,
});

Use this when:

  • You have fixed headers, footers, or sidebars that shouldn't be affected by the transform
  • You notice visual jitter or stuttering on elements that shouldn't move
  • You have a complex layout where only specific content should receive the smooth effect

Manual Control (Without Autoplay)

const scroller = createSlowScroll({
  target: ".content",
  speed: 30,
  autoplay: false, // Disable autoplay
});

// Start manually when needed
document.getElementById("startBtn").addEventListener("click", () => {
  scroller.start();
});

document.getElementById("stopBtn").addEventListener("click", () => {
  scroller.stop();
});

With Bounce Effect ↕︎

const scroller = createSlowScroll({
  target: ".content",
  speed: 24, // 24 pixels per second
  bounce: true, // Enable bounce at boundaries
  onDirectionChange: (direction) => {
    console.log(`Now scrolling: ${direction}`); // 'up', 'down', 'left', or 'right'
  },
});
// Starts automatically

Notes:

  • When bounce is false, scrolling stops when reaching page boundaries
  • When bounce is true, scroll direction automatically reverses at boundaries

Horizontal Scrolling →

const scroller = createSlowScroll({
  target: ".horizontal-content",
  isHorizontal: true, // Enable horizontal scrolling
  speed: 30, // Scroll right at 30px/s
});
// Starts automatically

Reverse Direction Scrolling ↑←

Use negative speed values to scroll in the opposite direction:

// Scroll up instead of down
const upScroller = createSlowScroll({
  target: ".content",
  speed: -30, // Negative speed = scroll up
});

// Scroll left instead of right
const leftScroller = createSlowScroll({
  target: ".horizontal-content",
  isHorizontal: true,
  speed: -30, // Negative speed = scroll left
});

Pause on User Interaction

Pause scrolling when user touches or moves mouse over the scroll area:

const scroller = createSlowScroll({
  target: ".content",
  speed: 30,
  pauseOnTouch: true, // Pause when user touches (useful for mobile/tablet)
  pauseOnMouseMove: true, // Pause when mouse is moving (useful for desktop)
});
// Scrolling automatically resumes when user stops interacting

Use cases:

  • pauseOnTouch: Prevents auto-scroll from interfering with user's touch scrolling on mobile devices
  • pauseOnMouseMove: Pauses when user moves mouse, allowing them to interact with content
  • Both options work together - enable one or both based on your needs

Dynamic Speed Control

const scroller = createSlowScroll({
  target: ".content",
  speed: 30,
});

// Change speed dynamically (automatically restarts if running)
scroller.setSpeed(50); // Speed up to 50px/s
scroller.setSpeed(15); // Slow down to 15px/s

// Example: Speed control with buttons
document.getElementById("speedUpBtn").addEventListener("click", () => {
  const config = scroller.getConfig();
  scroller.setSpeed(config.speed + 10);
});

document.getElementById("slowDownBtn").addEventListener("click", () => {
  const config = scroller.getConfig();
  scroller.setSpeed(Math.max(5, config.speed - 10)); // Minimum 5px/s
});

Without Interpolation (Compare Performance)

const scroller = createSlowScroll({
  target: ".content",
  speed: 15, // 15 pixels per second
  interpolation: false, // Disable for comparison
  onBoundaryReached: (boundary) => {
    console.log(`Reached ${boundary}, stopping`); // 'top', 'bottom', 'left', or 'right'
  },
});
// Starts automatically

Check Status

// Check if currently running
if (scroller.isRunning()) {
  console.log("Scrolling is active");
}

// Get current configuration
const config = scroller.getConfig();
console.log(`Speed: ${config.speed}px/s, Horizontal: ${config.isHorizontal}`);

API Reference

Methods

| Method | Parameters | Returns | Description | | -------------------- | ------------------ | --------- | ----------------------------------------------------------------------------- | | start() | None | void | Starts the auto-scrolling. Does nothing if already running. | | stop() | None | void | Stops the auto-scrolling and resets transform states. | | setSpeed(newSpeed) | newSpeed: number | void | Updates scroll speed in pixels per second. Automatically restarts if running. | | isRunning() | None | boolean | Returns true if currently scrolling, false otherwise. | | getConfig() | None | object | Returns a copy of the current configuration object. |

Configuration Options

| Option | Type | Default | Description | | ----------------------- | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | target | string \| HTMLElement | 'body' | CSS selector or DOM element of the scrollable container. | | interpolationTarget | string \| HTMLElement | null | CSS selector or DOM element to apply interpolation transform. If not specified, uses target for window scrolling, or the scrollable container itself for element scrolling. | | speed | number | 30 | Scroll speed in pixels per second (e.g., 24 = 24px/second). Positive values scroll down/right, negative values scroll up/left. Use 0 to pause. | | interpolation | boolean | true | Enable transform interpolation for smooth visual experience. | | bounce | boolean | false | Reverse scroll direction when reaching boundaries. | | isHorizontal | boolean | false | Scroll horizontally instead of vertically. | | autoplay | boolean | true | Start scrolling automatically when instance is created. | | pauseOnTouch | boolean | false | Pause scrolling when user touches the scroll area (useful for mobile). | | pauseOnMouseMove | boolean | false | Pause scrolling when mouse is moving over the scroll area. | | userScrollResumeDelay | number | 100 | Time in milliseconds to wait before resuming auto-scroll after user scrolling stops (iOS/iPadOS only). Increase if momentum scrolling feels interrupted. | | onDirectionChange | function | null | Callback function called when scroll direction changes (with bounce enabled). Receives new direction as parameter. | | onBoundaryReached | function | null | Callback function called when boundary is reached (with bounce disabled). Receives boundary type as parameter. |

Development

Run Demo Locally

cd demo
npm install
npm run dev

Opens the demo at http://localhost:3000

License

MIT

Author

Yamato Iizuka