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

@meetreeve/gamify

v0.1.0

Published

Generic gamification layer for Reeve surfaces — types, services, data hooks

Downloads

626

Readme

@meetreeve/gamify

Generic gamification layer for Reeve surfaces. Provides types, injectable API client, and data hooks (level, achievements, streak, XP transactions). Decoupled from any specific backend — consumer provides base URL + auth header via GamifyProvider.

Usage

import { GamifyProvider, useUserLevel, useAchievements, useStreak, useXPTransactions } from '@meetreeve/gamify';

<GamifyProvider baseUrl="https://api.example.com/api" getAuthHeader={() => `Bearer ${token}`}>
  <App />
</GamifyProvider>

Celebration / "game-win feel" primitives (@meetreeve/gamify/reveal)

The net-new desire/celebration primitives — LevelUpReveal, ShakingLock, Fireworks, ConfettiBurst, RewardClaim — plus their palette helpers live in the /reveal subpath. They are the only place that pulls in canvas-confetti and the full-screen choreography, so they are kept off the main barrel to keep first paint light. Code-split them with React.lazy / dynamic import:

import { lazy, Suspense, useState } from 'react';

// Off first paint — only loaded when a server-confirmed rung change occurs.
const LevelUpReveal = lazy(() =>
  import('@meetreeve/gamify/reveal').then((m) => ({ default: m.LevelUpReveal })),
);

function Cockpit() {
  const [reveal, setReveal] = useState(null);
  // ... when the SERVER confirms a rung transition (never optimistically):
  // setReveal({ rungLabel: 'Rung 2 · Scaling', capabilities: ['Paid Ads'] });
  return (
    <Suspense fallback={null}>
      {reveal && (
        <LevelUpReveal
          {...reveal}
          major={reveal.major}          // R3/R4 → escalates to two-stage Fireworks
          onClose={() => setReveal(null)}
          onCTA={() => {/* route to the unlocked surface */}}
        />
      )}
    </Suspense>
  );
}

The reduced-motion gate (NON-NEGOTIABLE)

Every celebration routes through useReducedMotionGame() and ships a tasteful static / opacity fallback (no shake, no confetti, no typing). The gate + the lightweight useShake / useSparkle hooks are on the main barrel (no particle code), so you can use them without loading /reveal:

import { useReducedMotionGame, useShake, useSparkle, ReducedMotionGameProvider } from '@meetreeve/gamify';

ReducedMotionGameProvider value={boolean} force-overrides the OS preference (useful for tests, Storybook, or an in-app "reduce animations" toggle).

Primitive summary

| Primitive | Subpath | What it is | Reduced-motion fallback | |-----------|---------|------------|--------------------------| | useReducedMotionGame() | . | SSR-safe prefers-reduced-motion gate | — (it is the gate) | | useShake({ idle }) | . | transform-only idle "itch" + impact "rattle" | no shake | | useSparkle() | . | 3–5 short twinkles on demand | ≤1 static sparkle | | ConfettiBurst | /reveal | capped <canvas> confetti from lower corners | static "Unlocked" badge fade | | Fireworks | /reveal | two-stage staged shell burst (major rungs) | static "Unlocked" badge fade | | LevelUpReveal | /reveal | full-screen choreographed rung reveal (controlled, server-confirmed) | calm modal, static text + CTA | | ShakingLock | /reveal | locked "desire engine" (idle itch, rattle-on-tap, click-open on unlock) | static state + tap pulse | | RewardClaim | /reveal | fly-to-home-counters collect pattern | instant update |

CSS tokens export

package.json exports "./styles/tokens.css" pointing at src/styles/tokens.css (src/ is included in files). This is intentional — the CSS file is published from source, not from dist. If you ever remove src/styles from files, add a build step to copy tokens.css to dist/ and update the export path, or theme consumers will silently get 404s.

Restraint contract: particles are <canvas> only (capped ~80–120), animations are transform/opacity only (no layout/gesture props that forward to the DOM), rAF/timers auto-stop and clean up on unmount, and celebrations fire only on explicit trigger / server-confirmed unlock — never optimistically, never idle (the sole exception being ShakingLock's idle itch). LevelUpReveal must be mounted by the consumer only after the server confirms the rung transition.