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

@humaan/segue

v0.1.0

Published

Consumer-owned Route Transition coordination for Next.js

Readme

@humaan/segue

Segue coordinates consumer-owned Route Transitions around Next.js App Router navigation. Version 0.1.0 runs a Cover before navigation, keeps its temporary UI mounted while Next.js finishes the navigation, and then removes it. Your application supplies the markup, CSS, animation, and production interface behavior.

Use Segue when you need project-specific transition visuals assigned to exact destination paths. It isn't a ready-made animation component, and 0.1.0 doesn't run a post-commit Reveal or a Destination Entrance.

Quick start

This example adds a visible green Cover before navigation from / to /projects/field-study.

1. Check the requirements and install

You need:

  • Next.js >=16.3.1 <17
  • React >=19.2 <20
  • The Next.js App Router
pnpm add @humaan/segue

The package doesn't include CSS, an animation library, or a build plugin.

2. Define the destination manifest

Create lib/segue-manifest.ts. The explicit generics make the manifest's Preset and rendition data types identical to the types passed to createSegue in the next step.

import { defineManifest } from "@humaan/segue";

export type PresetName = "project-cover";
export type RenditionData = {
  src: string;
  width: number;
  height: number;
};

export const segueManifest = defineManifest<PresetName, RenditionData>({
  routes: [
    {
      path: "/projects/field-study",
      preset: "project-cover",
      imagesByRole: {},
    },
  ],
});

The root @humaan/segue export is server-safe. Each manifest entry matches one normalized destination pathname; it doesn't match a dynamic route pattern.

3. Create the typed client integration

Create components/route-transitions.tsx:

"use client";

import type { ReactNode } from "react";
import {
  createSegue,
  waitForAnimation,
  type PresetDefinition,
} from "@humaan/segue/client";
import {
  segueManifest,
  type PresetName,
  type RenditionData,
} from "../lib/segue-manifest";

type TransitionImageProps = {
  className?: string;
};

type RouteTransitionsProps = Readonly<{
  children: ReactNode;
}>;

const Segue = createSegue<
  PresetName,
  RenditionData,
  TransitionImageProps
>();

const presets = {
  "project-cover": Segue.definePreset({
    imageRoles: [],
    reducedMotion: "skip",
    render: () => <div className="segue-cover" data-cover />,
    animate: async ({ root, navigation }) => {
      const cover = root.querySelector<HTMLElement>("[data-cover]");
      if (!cover) throw new Error("The project Cover did not mount");

      const animation = cover.animate(
        [
          { transform: "translateX(-100%)" },
          { transform: "translateX(0)" },
        ],
        {
          duration: 600,
          easing: "cubic-bezier(.76, 0, .24, 1)",
          fill: "forwards",
        },
      );
      await waitForAnimation(animation, navigation.signal);
    },
  }),
} satisfies Record<
  PresetName,
  PresetDefinition<PresetName, RenditionData, TransitionImageProps>
>;

export function RouteTransitions({ children }: RouteTransitionsProps) {
  return (
    <Segue.Provider manifest={segueManifest} presets={presets}>
      {children}
    </Segue.Provider>
  );
}

export function ProjectLink() {
  return (
    <Segue.Link href="/projects/field-study">
      View the field study
    </Segue.Link>
  );
}

A Route-Transition Preset defines its temporary UI and Cover animation. reducedMotion: "skip" prevents Segue from mounting or animating this Preset when the visitor prefers reduced motion.

4. Mount the Provider and add the CSS

Mount one Provider per browser window in a layout that remains mounted across the source and destination routes. The root layout is usually the correct location.

// app/layout.tsx
import type { ReactNode } from "react";
import { RouteTransitions } from "../components/route-transitions";
import "./globals.css";

export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
  return (
    <html lang="en">
      <body>
        <RouteTransitions>{children}</RouteTransitions>
      </body>
    </html>
  );
}
/* app/globals.css */
.segue-cover {
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  background: #b8f34a;
  transform: translateX(-100%);
}

Segue marks the temporary Preset host aria-hidden="true". Keep controls, announcements, and meaningful content outside it.

5. Add the routes and run the application

// app/page.tsx
import { ProjectLink } from "../components/route-transitions";

export default function HomePage() {
  return (
    <main>
      <h1>Projects</h1>
      <ProjectLink />
    </main>
  );
}
// app/projects/field-study/page.tsx
export default function FieldStudyPage() {
  return (
    <main>
      <h1>Field study</h1>
    </main>
  );
}
pnpm dev

Open the local URL and select View the field study. The green Cover crosses the current route, Next.js navigates, and Segue removes the Cover when /projects/field-study commits.

Behavior and ownership

  • Manifest routes are exact normalized pathnames. An unlisted destination still navigates without a Preset.
  • A Route-Transition Override can provide one-off consumer choreography. Returning false, throwing, or rejecting falls back to the destination's Preset.
  • routeTransition={false} skips the Override, Preset, and Image Warming, but Segue still coordinates pending state, history, and navigation settlement.
  • navigate() resolves after Segue invokes router or document navigation, not after route settlement. It can instead resolve { status: "ignored", reason: "busy" } or { status: "ignored", reason: "same-location" }.
  • Presets and Overrides receive navigation.signal. waitForAnimation() connects that signal to native Web Animations API animations or stoppable thenable controls.

Version 0.1.0 removes Preset UI when navigation settles and doesn't provide a post-commit Reveal. Your application owns visual design, reduced-motion policy, scroll and interaction behavior, focus, accessibility, monitoring, and Destination Entrance animation.

Documentation

Continue with the user documentation source:

Internal design material: