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

kineto

v0.1.0

Published

A drop-in library of beautifully animated, copy-paste React components — shadcn DNA, motion-first.

Readme

Kineto

A drop-in library of beautifully animated, copy-paste React components — in the spirit of shadcn/ui, but with motion as a first-class concern, powered by Motion (package motion).

The defining idea is the same as shadcn: components are source you own, not an installed black box. Every component is self-contained, readable, themeable via CSS variables, and droppable into any React + Tailwind project with zero custom runtime or provider required.

.                         # repo root = the published `kineto` npm package
  src/
    lib/
      cn.ts               # cn() = twMerge(clsx(...))
      gap.ts              # spacing scale helper
      format-time.ts      # relative/absolute time formatting
      motion-presets.ts   # variants + transition tokens (single source of truth)
      use-reduced-motion.ts
    components/
      ui/                 # primitives: button, badge, card, input, label, separator,
                          #   switch, tooltip, avatar, select, dropdown-menu, progress,
                          #   segmented-control, skeleton, dialog, tabs, accordion, …
      application/        # app surfaces: stat-card, data-table, sidebar, logo-cloud, …
      charts/             # data viz: area, bar, line, donut + chart-tooltip
    styles/
      theme.css           # SHIPPED: tokens (:root + .dark) + Tailwind v4 @theme + @utility
      base.css            # SHIPPED (optional): opinionated document styles
      kineto.css          # docs-site aggregator — imports both; not published
    index.ts              # public barrel for the npm package
  tsup.config.ts          # library build → dist/ (ESM, per-component + barrel)
  site/                   # the docs site (separate Next.js app; imports the library source)

Installation — three ways to consume

kineto is both a published library and a copy-the-source registry. Pick whichever fits.

1. shadcn CLI (copy the source into your project — the community default)

Every component is served as a shadcn-spec registry item, so the CLI writes the real source (plus its internal deps like cn and motion-presets) into your own components/ and installs the npm deps it needs:

# add the tokens once, then any component(s)
npx shadcn@latest add https://<your-site>/r/kineto-theme.json
npx shadcn@latest add https://<your-site>/r/button.json

registryDependencies resolve automatically (e.g. date-picker pulls in button, calendar, and popover). Browse the index at https://<your-site>/r/registry.json. The theme item carries the color tokens; the utility layer it doesn't cover — bg-dots/bg-grid/bg-grain, the bg-gradient-* set, shadow-soft/shadow-lift, font mappings — comes from @import "kineto/theme.css". GradientText and GradientBorder need that import specifically.

2. npm package (install the built library)

npm i kineto

Then wire it into your Tailwind entry. Both lines are required — the @import defines the tokens, and the @source is what makes Tailwind generate CSS for the classes inside our compiled components. Tailwind v4 never scans node_modules on its own, so without the @source you get a clean build and completely unstyled components:

/* index.css / globals.css */
@import "tailwindcss";

@import "../node_modules/kineto/theme.css";
@source "../node_modules/kineto/**/*.js";

/* Optional — opinionated document styles (body, selection, focus ring, scrollbars). */
@import "../node_modules/kineto/base.css";

/* Your customizations go after this: redefine any token on :root / .dark to re-skin. */
import { Card } from "kineto/card";        // subpath — always tree-shakes, always server-safe
import { Button } from "kineto";           // barrel — fine, but see the Next note below

We ship no pre-built CSS. Every class resolves in your Tailwind build from your own config, so you get only the utilities you actually use and your overrides win normally.

Both forms are tree-shakeable. dist/index.js is a re-export map over the per-component files, not a bundle, so each component stays its own module and keeps its own "use client" boundary — the 20 directive-free primitives (badge, input, container, …) render on the server through the barrel too.

Next.js users: add one line. Next turns every "use client" module reachable from a barrel into a client entry, and client entries are graph roots that webpack will not shake away. Next's own remedy rewrites barrel imports to subpath imports at compile time:

// next.config.mjs
export default { experimental: { optimizePackageImports: ["kineto"] } };

Measured, Next 14 App Router, page rendering one <Button> (First Load JS):

| import | plain | with optimizePackageImports | | --- | --- | --- | | from "kineto" | 476 kB | 131 kB | | from "kineto/button" | 131 kB | 131 kB |

Bundlers that shake on the module graph directly — Vite, Rollup, plain webpack outside the RSC pipeline — need no configuration: there the barrel and the subpath emit byte-identical output (3,085 B for one Button, vendor external). If you would rather not touch next.config.mjs, use the subpath import; it is the one form that is optimal everywhere.

All peers (react, react-dom, motion) are external; Radix/lucide/etc. ship as deps.

3. Manual copy

  1. Copy src/lib/cn.ts, src/lib/motion-presets.ts, and (optionally) use-reduced-motion.ts.
  2. Copy any component file from src/components/**.
  3. Copy the design tokens from src/styles/theme.css into your global stylesheet (and src/styles/base.css if you want the document-level styles too).

Each component imports only from react, motion/react, @/lib/cn, @/lib/motion-presets, Radix (where applicable), and lucide-react. Drop it in and it renders and animates — no wiring.

Tailwind CSS v4 is used for styling (CSS-first config — see below).

Theming with CSS variables

All colors, radii, and shadows read from HSL CSS variables (like shadcn). Components never hardcode a hex value, so the entire library re-skins when you change the tokens or toggle the .dark class.

/* globals.css */
:root {
  --background: 38 36% 97%;    /* warm near-white */
  --foreground: 24 12% 12%;    /* warm near-black */
  --primary: 24 14% 13%;       /* ink — buttons & controls */
  --brand: 22 92% 52%;         /* the one orange accent */
  --success: 142 58% 37%;
  --warning: 36 95% 46%;
  /* ...etc */
  --radius: 0.85rem;
}

.dark {                        /* dark is the default theme */
  --background: 24 14% 7%;     /* warm charcoal */
  --foreground: 40 18% 92%;
  --primary: 40 30% 96%;       /* near-white ink */
  --brand: 22 95% 57%;
  /* ...etc */
}

The identity keeps ink (near-black / near-white) as the primary for buttons and controls, and reserves a single orange --brand accent for emphasis, focus rings, and data. Beyond the shadcn base tokens it adds status colors (--success, --warning), a 5-stop chart palette (--chart-1--chart-5 — orange + warm greys) so data-display components stay on-theme in both modes, and a gradient layer (see below). Use the brand Button/Badge variants for orange CTAs.

Gradients

Gradients are part of the token system, not one-off linear-gradient(...) calls sprinkled through components. Two stops and one angle compose every gradient the library ships:

| Token | Default | Notes | | --- | --- | --- | | --gradient-from | unset--brand | Bare H S% L% triple, like every other color token. | | --gradient-to | unset--chart-3 | The accent's lighter sibling in every preset. | | --gradient-angle | 135deg | Applies to the linear ramps. |

Leaving the stops unset is the intended default: the utilities read them as var(--gradient-from, var(--brand)), so the ramp follows whatever accent is in scope — light, dark, a preset, or a subtree that re-colors --brand. That fallback is deliberate. Declaring --gradient-from: var(--brand) on :root would substitute there and keep serving the light accent to a nested .dark section. Pin the stops only when the ramp shouldn't track the accent:

:root {
  --gradient-from: 265 85% 58%;   /* violet → cyan, regardless of --brand */
  --gradient-to: 190 90% 55%;
  --gradient-angle: 100deg;
}

The utilities (all set background-image only, so they stack with text-* / border-*):

| Utility | Use | | --- | --- | | bg-gradient-brand | The accent ramp at full strength. Pair with text-brand-foreground. | | bg-gradient-brand-soft | Same ramp at wash strength, under readable foreground text. | | bg-gradient-brand-loop | Seamless double-width ramp for panning animations. | | bg-gradient-surface | Neutral top-lit sheen for raised surfaces. | | bg-gradient-hairline | A 1px border that fades along its run. | | bg-gradient-mesh | Atmospheric multi-blob backdrop for heroes and empty states. | | bg-gradient-fade | Surface → transparent, for scroll edges. | | text-gradient-brand | Gradient-filled text (static). |

For one-off directions the stops are also exposed as real colors, so Tailwind's own gradient utilities work off the themed ramp: bg-linear-to-r from-gradient-from to-gradient-to.

Two components add motion on top of the same tokens — GradientText (pans the ramp across the glyphs) and GradientBorder (a masked gradient hairline with an optional rotating sweep) — and Button, Badge, and FeaturedIcon each gained a gradient variant.

In Tailwind v4 the old tailwind.config.ts is replaced by a CSS-first @theme block that maps those tokens to utilities (bg-background, text-primary, rounded-lg, font-display, shadow-lift, …):

@theme inline {
  --color-background: hsl(var(--background));
  --color-primary: hsl(var(--primary));
  --radius-lg: var(--radius);
  /* ...etc */
}

To re-theme: change the token values. To go dark: add dark to the <html> class. That's the whole story — no component edits.

The animation system

Motion is systematic, not improvised. Everything references lib/motion-presets.ts:

  • Transition tokensspring.snappy, spring.soft, spring.bouncy, tween.smooth, tween.quick.
  • Reveal variantsfadeUp, fadeIn, scaleIn, slideInLeft/Right, blurIn.
  • Stagger helpersstaggerContainer(stagger, delay) + staggerItem.
  • Interaction presetsinteraction.hover, interaction.tap, interaction.cardHover.
  • ViewportviewportOnce for scroll-triggered reveals.

Principles baked in:

  • Respects prefers-reduced-motion. Wrap your app once in <MotionConfig reducedMotion="user"> (see src/components/site/providers.tsx) and all declarative reveals collapse to instant/opacity-only. Imperative loops like the marquee branch on useReducedMotion() and stop entirely.
  • Scroll reveals use whileInView with viewport={{ once: true, margin: "-15%" }}.
  • Transform & opacity only (plus an occasional filter: blur) — never layout-thrashing properties.
  • One engine. No CSS keyframes for component motion; even the accordion height reveal runs through Motion.

Repo scripts

The library lives at the repo root; the Next.js (App Router) docs site is a workspace member in site/ that imports the library source (via the @/* → ["../src/*","./src/*"] alias), so edits show up instantly with no rebuild.

pnpm install          # one hoisted install for the whole workspace

# docs site
pnpm dev              # runs site/ (Next dev)
pnpm site:build       # production build of the docs site (also generates /r/*.json)

# library
pnpm build:lib        # type-check (strict) + tsup → dist/ (what npm publishes)
pnpm typecheck:lib
  • / — a live showcase built from the real blocks.
  • /docs/<slug> — each component with install tabs (shadcn CLI + npm), an interactive props Playground, a live preview, the prop table, and one-click copy of the exact source file (read straight from disk, so it never drifts).
  • /r/<name>.json — the shadcn registry endpoint (set NEXT_PUBLIC_SITE_URL in production so cross-item registryDependencies URLs point at your deployed origin).

Stack

React 18 · TypeScript (strict) · Tailwind CSS v4 · Motion · Radix UI · lucide-react · Next.js (docs site). Fonts: Fraunces (editorial serif display) + Inter (body) + JetBrains Mono.

MIT licensed. The components are yours.