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

chronostasis

v0.1.0

Published

Pause animation rendering on blur. SolidJS adapter.

Readme

chronostasis

Pause background animation ticks while a heavy compositing effect runs on top.

chronostasis (クロノスタシス) — the visual illusion where the second hand of a clock appears to freeze for a moment when you first glance at it. (Wikipedia)

This module provides a tiny shared-state primitive that lets you suspend the dynamic background of a page (clock displays, CSS animations, setInterval / requestAnimationFrame side effects) for the duration of a heavy compositing effect running on top of it.

  • Zero dependencies
  • Framework-agnostic vanilla TypeScript core
  • SolidJS adapter included; bridge to React / Vue / vanilla DOM in a few lines
  • Lease-style acquire counter — multiple callers can hold chronostasis at the same time

Why

Compositing effects like backdrop-filter: blur are expensive precisely because the browser has to re-blur every time the underlying pixels change. If the layer underneath is completely still, the browser can cache the blurred result on its compositing layer and paint it once — which makes the effect viable on low-end hardware (older iPads, low-cost tablets, education tablets, etc.).

The same problem appears beyond blur. Long opacity transitions, transform springs, and other "recomposite the layer underneath every frame" effects all suffer when background work keeps mutating that layer. While chronostasis is held, you suspend those background ticks so compositing resources can go to the foreground effect.

Install

npm install chronostasis
pnpm add chronostasis
yarn add chronostasis

solid-js is an optional peer dependency — only required if you import the chronostasis/solid entry point.

Usage

Vanilla (any framework)

import {
  inChronostasis,
  requestChronostasis,
  subscribeChronostasis,
} from "chronostasis";

// 1. Pause a ticker while chronostasis is held.
let timer: number | undefined;
subscribeChronostasis((held) => {
  if (held) {
    clearInterval(timer);
    timer = undefined;
  } else {
    timer = setInterval(tick, 1000);
  }
});

// 2. Acquire chronostasis around a heavy effect.
function openBlurredPicker() {
  const release = requestChronostasis();
  try {
    // ... show the picker with backdrop-filter: blur ...
  } finally {
    // call release() when the picker closes
  }
}

requestChronostasis() returns a release function. When several callers hold leases at the same time, chronostasis stays held until the last one releases.

SolidJS

import { onCleanup, createEffect, on } from "solid-js";
import { requestChronostasis } from "chronostasis";
import { useChronostasis, useChronostasisBodyClass } from "chronostasis/solid";

// Toggle `body.chronostasis` whenever chronostasis is held.
// Pair this with CSS like:
//   body.chronostasis .star { animation-play-state: paused; }
function App() {
  useChronostasisBodyClass();
  return <Routes />;
}

// Pause a ticker reactively.
function Clock() {
  const held = useChronostasis();
  createEffect(on(held, (isHeld) => {
    if (isHeld) return;
    const id = setInterval(tick, 1000);
    onCleanup(() => clearInterval(id));
  }));
}

// Hold chronostasis for the lifetime of a component.
function BlurredPicker() {
  onCleanup(requestChronostasis()); // released automatically on unmount
  return <div class="picker" />;
}

Pairing requestChronostasis() with onCleanup makes the release structurally guaranteed — there is no "forgot to leave" trap.

Other frameworks

To bridge to React / Vue / vanilla DOM, wrap subscribeChronostasis in your framework's external-store primitive:

// React example
import { useSyncExternalStore } from "react";
import { inChronostasis, subscribeChronostasis } from "chronostasis";

export const useChronostasis = () =>
  useSyncExternalStore(subscribeChronostasis, inChronostasis, inChronostasis);

See src/solid.ts for a reference adapter.

API

Core (chronostasis)

inChronostasis(): boolean

Synchronous getter. Returns true while at least one lease is held.

requestChronostasis(): () => void

Acquires one lease and returns its release function. The release function is idempotent — calling it more than once is harmless.

subscribeChronostasis(listener: (held: boolean) => void): () => void

Subscribes to state transitions. The listener fires only at the boundaries (0 → 1 and 1 → 0); intermediate changes to the acquire count do not fire it. Returns an unsubscribe function. Adding the same listener multiple times has no effect (the underlying Set deduplicates).

SolidJS (chronostasis/solid)

Both must be called inside a reactive owner (component setup).

useChronostasis(): Accessor<boolean>

Reads chronostasis state as a Solid reactive accessor.

useChronostasisBodyClass(className?: string): void

Toggles a class (default: "chronostasis") on document.body whenever chronostasis state changes. Useful for pausing CSS animations in bulk via a CSS selector:

body.chronostasis .star {
  animation-play-state: paused;
}

License

MIT © mrksye