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

reel-it

v1.0.1

Published

Turn any page into a film you scrub by scrolling. A fixed full-bleed video background whose timeline is driven by scroll, plus scroll-pinned content reveals. Framework-agnostic core + React API.

Readme

reel-it pins a full-bleed video behind your page and maps scroll progress to the video's timeline. Scroll down and the film moves forward. Scroll up and it rewinds. Content can fade in at exact points on that same timeline.

The Mental Model

Every reel has five pieces:

  1. Clip - an MP4 encoded for seeking. For crisp scrubbing, every frame should be a keyframe.
  2. Track - a tall wrapper, such as height: 360vh. This is the scroll distance.
  3. Stage - a sticky, full-screen layer that holds the video while the track scrolls.
  4. Content - headings, copy, or UI that sits over the stage.
  5. Reveals - optional progress windows, such as 0.10 -> 0.35, that fade content in as the film reaches that point.

The core formula is:

progress = clamp(-track.top / (track.height - viewport.height), 0, 1)
video.currentTime = progress * video.duration

Everything else is a wrapper around that idea.

Quickstart

npm install reel-it

npx reel-it prepare ./raw/color-water.mp4 \
  --seconds 10 --quality balanced --name color-water

npx reel-it prepare "https://www.pexels.com/video/colorful-tropical-fish-swimming-in-aquarium-36004282/" \
  --seconds 10 --quality balanced --name tropical-fish

npx reel-it prepare "https://www.pexels.com/video/high-speed-photography-of-colorful-ink-diffusion-in-water-9669111/" \
  --seconds 10 --quality balanced --name color-ink

npx reel-it prepare "https://www.pexels.com/video/washing-a-paint-brush-on-a-glass-of-water-3795829/" \
  --seconds 10 --quality balanced --name paint-brush
import { Reel, Reveal } from "reel-it";
import "reel-it/styles.css";

export default function Hero() {
  return (
    <Reel
      src="/color-water.mp4"
      poster="/color-water-poster.jpg"
      length="360vh"
      preload="eager"
      overlay="rgba(0,0,0,.28)"
    >
      <div style={{ position: "sticky", top: 0, height: "100vh", display: "grid", placeItems: "center" }}>
        <Reveal from={0.08} to={0.32}>
          <h1>Scroll is the timeline</h1>
        </Reveal>
      </div>
    </Reel>
  );
}

Serve the page from a real HTTP server. Video scrubbing depends on normal browser video loading and HTTP range requests; opening the HTML file directly is not a reliable test.

Prepare A Crisp Clip

Most videos are encoded with sparse keyframes, which makes random seeks lag or smear. reel-it prepare re-encodes the clip as all-intra H.264 so each frame is directly seekable.

npx reel-it prepare ./ocean.mov
npx reel-it prepare ./ocean.mov --quality sharp
npx reel-it prepare ./ocean.mov --height 1440 --crf 18 --out public/ocean
npx reel-it prepare "https://www.youtube.com/watch?v=ID" --start 60 --seconds 12 --quality balanced
npx reel-it prepare "https://www.pexels.com/video/colorful-tropical-fish-swimming-in-aquarium-36004282/" --seconds 10 --quality balanced --name tropical-fish
npx reel-it prepare "https://www.pexels.com/video/high-speed-photography-of-colorful-ink-diffusion-in-water-9669111/" --seconds 10 --quality balanced --name color-ink
npx reel-it prepare "https://www.pexels.com/video/washing-a-paint-brush-on-a-glass-of-water-3795829/" --seconds 10 --quality balanced --name paint-brush

If Pexels blocks command-line download for a page URL, download the video in the browser and run reel-it prepare on the local file:

npx reel-it prepare ./tropical-fish.mp4 --seconds 10 --quality balanced --name tropical-fish
npx reel-it prepare ./color-ink.mp4 --seconds 10 --quality balanced --name color-ink
npx reel-it prepare ./paint-brush.mp4 --seconds 10 --quality balanced --name paint-brush

Quality presets:

| Preset | Height | CRF | Use it for | | --- | ---: | ---: | --- | | small | 720 | 26 | quick tests and small backgrounds | | balanced | 1080 | 22 | the default, good hero quality | | sharp | 1440 | 18 | crisp demos and portfolio pages |

Lower CRF means sharper output and larger files. All-intra video is always larger than normal delivery video, so keep clips short and use preload="eager" only for hero-sized assets that can fit comfortably in memory.

Output:

reel-out/
  ocean.mp4
  ocean-poster.jpg
  preview.html
  reel.core.js

The generated preview.html is intentionally plain so you can judge the encoded clip without heavy filters hiding compression.

Plain HTML

<link rel="stylesheet" href="node_modules/reel-it/dist/styles.css" />

<div data-reel-track style="height: 360vh">
  <div class="reel-stage">
    <video
      data-reel-video
      data-reel-preload="eager"
      src="ocean.mp4"
      poster="ocean-poster.jpg"
      muted
      playsinline
    ></video>
    <div class="reel-overlay" style="background: rgba(0,0,0,.28)"></div>
  </div>

  <div class="reel-content">
    <div data-reel-reveal="0.08,0.32">
      <h1>Scroll is the timeline</h1>
    </div>
    <div data-reel-reveal="0.44,0.66,0.78,0.9">
      <p>This line fades in, then fades out.</p>
    </div>
  </div>
</div>

<script type="module">
  import { auto } from "reel-it/core";
  auto();
</script>

React API

<Reel> creates the track, stage, video, and content layers.

| Prop | Default | Notes | | --- | --- | --- | | src | required | MP4 URL | | poster | none | image shown before the first frame | | length | "300vh" | scroll distance for the whole film | | duration | video duration | scrub only the first N seconds | | smoothing | 0.3 | lerp amount per animation frame | | seek | "precise" | use "fast" only for very heavy clips | | preload | "native" | "eager" fetches the whole clip as a blob | | overlay | none | CSS background for a dim/tint layer |

<Reveal from={0.1} to={0.35}> fades and rises its children over a progress window.

useScrollProgress() returns the current reel progress, 0 to 1, anywhere inside a <Reel>.

Core API

import { createReel, createReveals, preloadFilm } from "reel-it/core";

Use the core when you want to wire the DOM yourself or build your own framework wrapper.

const reel = createReel({
  track: document.querySelector("[data-reel-track]")!,
  video: document.querySelector("[data-reel-video]")!,
  smoothing: 0.3,
  seek: "precise",
});

reel.onProgress((progress) => {
  console.log(progress);
});

Local Development

git clone https://github.com/sayantan94/reel.git
cd reel
npm install
npm run build
python3 -m http.server 4173 --directory examples

Then open http://localhost:4173.

The package is published as reel-it. The CLI can be called as reel-it from npx, and the installed binary also exposes reel for shorter local scripts.

Deploy The Website

The repo includes vercel.json, so Vercel can build the package and serve the static website from examples/.

npm run build
npx vercel

Vercel settings:

Build Command: npm run build
Output Directory: examples

Keep prepared MP4 files under examples/assets/ for the marketing site, or under public/ in an app that consumes reel-it.

npm Release

npm run pack:check
npm version patch
npm publish --access public

[email protected] is published on npm. Future releases should bump the version before publishing. The package contains the runtime, React adapter, CSS, and reel / reel-it CLI binaries.

Manual Encoding

If you want to prepare a file yourself, keep the dense keyframes and sharp scaler:

ffmpeg -i source.mp4 -an -vf "scale=-2:1080:flags=lanczos" \
  -c:v libx264 -profile:v high -pix_fmt yuv420p -preset slow \
  -g 1 -x264-params keyint=1:scenecut=0 -crf 22 \
  -movflags +faststart film.mp4

For sharper output, use scale=-2:1440:flags=lanczos and -crf 18.

Examples

The examples/ folder is a static website built with reel-it itself:

  • index.html - docs and landing page with a scroll-scrubbed background
  • pexels.html - full-screen prepared color-water example
  • hero.html - large headline over film
  • color.html - centered copy over ink
  • cosmos.html - dark scrim with reveal copy
  • minimal.html - background only

License

MIT