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

@rosado-io/streakr

v1.4.1

Published

A framework-agnostic presentation layer for contribution and activity calendars.

Readme

Streakr

npm version License: MIT CI

Streakr is a framework-agnostic presentation layer for contribution and activity calendars. You own data acquisition, credentials, caching, and persistence. Streakr receives one serializable contract and renders a responsive heatmap, mobile ring, source filters, year navigation, lifecycle states, and statistics.

your API / database / file / build script
                    ↓
              StreakrDay[]
                    ↓
       heatmap · ring · filters · stats

The package contains no network clients, token handling, filesystem access, or runtime dependencies. Streakr is published as ESM.

Installation

npm install @rosado-io/streakr
# pnpm add @rosado-io/streakr
# yarn add @rosado-io/streakr

Quickstart

<div id="streakr"></div>
import { createStreakr } from "@rosado-io/streakr";
import "@rosado-io/streakr/styles.css";

const streakr = createStreakr({
  target: document.querySelector<HTMLElement>("#streakr")!,
  years: [2025, 2026],
  year: 2026,
  days: [
    {
      date: "2026-07-28",
      count: 7,
      sources: { work: 5, personal: 2 },
    },
  ],
  sources: [
    { key: "work", name: "Work", color: "#39d353" },
    { key: "personal", name: "Personal", color: "#4f8cff" },
  ],
  onYearChange(year) {
    void loadYear(year);
  },
});

async function loadYear(year: number) {
  streakr.update({ year, status: "loading" });
  try {
    const days = await fetch(`/api/activity?year=${year}`).then((response) => response.json());
    streakr.update({ days, status: "ready" });
  } catch {
    streakr.update({
      status: "error",
      errorMessage: "Activity could not be loaded.",
    });
  }
}

Pass multiple years in one days array when they are already available. Streakr selects the requested year without calling application code.

Data contract

interface StreakrDay {
  readonly date: string; // YYYY-MM-DD
  readonly count: number;
  readonly sources?: Readonly<Record<string, number>>;
}

Streakr validates its inputs before rendering:

  • Dates must be real calendar dates in YYYY-MM-DD form.
  • Counts must be non-negative safe integers.
  • Dates and source keys must be unique.
  • Every source key in a day must be declared in sources.
  • When sources is present, its values must add up to count.
  • year must appear in years.

String dates prevent UTC parsing from shifting a contribution into an adjacent local day.

API

createStreakr(options)

| Option | Type | Default | Purpose | | ---------------- | ------------------------------------- | ------------- | ---------------------------------------- | | target | HTMLElement | required | Element that receives the component. | | days | readonly StreakrDay[] | required | Serializable activity data to present. | | years | readonly number[] | required | Available year tabs. | | year | number | last year | Selected year. | | today | string | current date | YYYY-MM-DD reference for year-to-date. | | status | loading \| empty \| ready \| error | ready | Presentation lifecycle state. | | errorMessage | string | built-in copy | Message rendered by the error state. | | sources | readonly StreakrSource[] | host presets | Labels, colors, icons, and filter keys. | | theme | dark \| light \| system | dark | Visual theme. | | accent | six-digit hex color | #39d353 | Accent and optional heatmap tint. | | tintHeatmap | boolean | true | Derive heat levels from the accent. | | showSources | boolean | true | Show source filter chips when useful. | | showStats | boolean | true | Show computed records. | | onYearChange | (year) => void | — | Observe a user-selected year. | | onSourceToggle | (key, enabled, sourceState) => void | — | Observe source filter changes. |

The instance exposes:

streakr.update({ days, status: "ready" });
streakr.setYear(2025);
streakr.setSources({ work: false });
streakr.destroy();

target is intentionally absent from update(). Destroy and recreate an instance to move it.

Visual sources

DEFAULT_SOURCES contains GitHub, GitLab, and Bitbucket presentation presets. AGENT_SOURCES contains Claude, Codex, opencode, Copilot, Kimi, and Antigravity presets. They do not fetch or classify data.

import { AGENT_SOURCES, DEFAULT_SOURCES, createStreakr } from "@rosado-io/streakr";

createStreakr({
  target,
  years,
  days,
  sources: [...DEFAULT_SOURCES, ...AGENT_SOURCES],
});

A custom icon is a factory returning an SVG node, so Streakr never inserts consumer-provided HTML:

const source = {
  key: "work",
  name: "Work",
  color: "#39d353",
  icon() {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("viewBox", "0 0 16 16");
    return svg;
  },
};

Recipes

Recipes are application-owned examples, not runtime exports:

Copy a recipe, adapt it, or ignore it and produce the contract however you want. Keep credentials in a server, CI job, or local build process—not in browser code.

Responsive and accessible interaction

Containers at least 520px wide render a weekly heatmap. Smaller containers use the radial ring. Both views are keyboard accessible:

  • Year and source controls use native buttons and expose their active state.
  • Heatmap days use one roving tab stop and arrow-key navigation.
  • Ring days support arrows, Home, End, Enter, and Space.
  • Loading, empty, and error states have accessible announcements.
  • Motion respects prefers-reduced-motion.

Future days

In the current year, days after today are future days. The ring draws them transparent and non-interactive; the heatmap keeps them visible and focusable with a "No contributions" label so keyboard navigation covers a uniform grid.

Styling

Import @rosado-io/streakr/styles.css. Override --sk-* custom properties on .sk-root for deeper customization. The package has no external CSS dependencies.

Development

pnpm install
pnpm typecheck
pnpm lint
pnpm test:ci
pnpm build
pnpm build:demo
pnpm audit:dead-code
pnpm check:package

License

MIT