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

card-motion

v0.2.0

Published

Juicy playing-card animations for React — shuffle, deal, play, 3D tilt and a WebGL background. Powered by GSAP.

Readme

🃏 card-motion

Juicy playing-card animations for React.

Shuffle, deal, select and play with GSAP timelines — a ready-made card table, plus the headless engine to build your own game.

npm version npm downloads bundle size license


Features

  • <CardTable> — a full deck with shuffle, deal, select, play and reset, wired up.
  • Headless enginesuseCardTable (deck/hand/table) and useCardPiles (any piles: solitaire, discards, foundations) own the state and the GSAP timelines; you render the cards.
  • Drag & drop — primitives for board games: the library owns the pointer mechanics and snap-back, you own the rules.
  • Composable layouts — swap in fan / row / stack, or write your own.
  • Accessible — keyboard-operable, ARIA roles, a live region, and prefers-reduced-motion support.
  • TypeScript-first, tree-shakeable ESM + CJS, runs in Next.js (App Router) as a client component.

Install

pnpm add card-motion gsap

react and gsap are peer dependencies. Import the stylesheet once, in your app entry:

import 'card-motion/styles.css';

Quick start

import { CardTable } from 'card-motion';
import 'card-motion/styles.css';

export default function App() {
  return (
    <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
      <CardTable handSize={8} />
    </div>
  );
}

<CardTable> fills its positioned parent, so give it a sized, position: relative container.

| Prop | Default | Description | | --- | --- | --- | | handSize | 8 | Cards dealt into the hand. | | cardWidth | 96 | Card width in px (auto-shrinks on narrow screens). | | controls | true | Show the built-in control bar. | | selectable | true | Click a hand card to select / deselect it. | | deck | full 52 | Custom deck (CardData[]). |

Drive it imperatively with a ref (CardTableHandle): shuffle, deal, play, playSelected, clearTable, reset, toggleCard.

Headless

Render your own cards and controls; the hook owns the state, the timelines and selection.

import { useCardTable, Card } from 'card-motion';

function Table() {
  const { cards, stageRef, registerCard, deal, playSelected, toggleCard, selected, counts } =
    useCardTable({ handSize: 7 });

  return (
    <div className="cm-stage" ref={stageRef}>
      {cards.map((c) => (
        <Card
          key={c.id}
          ref={(node) => registerCard(c.id, node)}
          rank={c.rank}
          suit={c.suit}
          selected={selected.has(c.id)}
          onClick={() => toggleCard(c.id)}
          style={{ position: 'absolute', top: 0, left: 0 }}
        />
      ))}
    </div>
  );
}

For anything beyond deck/hand/table, useCardPiles manages arbitrary piles with the same model. You declare each pile (its anchor and layout) and move cards with move / draw / gather / shuffle. Cards can carry any payload with a numeric id — the engine only reads id.

const { piles, move, draw, gather } = useCardPiles({
  piles: {
    deck: { anchor: (s) => ({ x: s.width / 2, y: 80 }), layout: stackLayout },
    hand: { anchor: (s) => ({ x: s.width / 2, y: s.height - 120 }), layout: fanLayout },
  },
});

Building blocks

  • Drag & drop<DragDropProvider onDrop> + <DropZone id accepts> + <DraggableCard id zone> to build solitaire and friends. onDrop fires on a valid drop; return false to reject (the card springs back).
  • useCardDrag — pointer dragging for engine-positioned cards. You give it a resolveDrop(id, point, stage) that picks a target (or rejects) and an onDrop that applies it; taps and drags are told apart, so click-to-select keeps working.
  • useCardInspect + <CardInspectLayer> — tap / hold / hover (or call open() from any event) to magnify a card. The hook handles the gesture and is movement-aware, so it yields to a drag; <CardInspectLayer> animates a FLIP magnify out of the source card over a dim backdrop. You render the enlarged content, the library owns the motion.
  • fan / row / stack — layout factories, e.g. fan({ spread: 0.6, maxSpacing: 98 }). Zero-config instances (fanLayout, rowLayout, stackLayout) are exported too.
  • <Card> — the card visual: corner indices, big pip, an optional holographic foil, and a pointer-driven 3D tilt.
  • <BackgroundShader> — an optional fullscreen WebGL swirl. <BackgroundShader colors={{ deep, warm, cool }} speed={1.2} />.
  • <DeckReveal> — a modal that spreads a pile so the player can browse and pick a card.
  • Timings — every engine takes an optional motion config (moveDuration, dealEase, selectLift, …); omit it and you get the built-in choreography.
  • UtilitiesbuildDeck(), shuffleInPlace(), cardLabel(rank, suit), SUITS, RANKS.

Accessibility

<CardTable> is keyboard- and screen-reader-friendly out of the box: arrow-key roving focus across the hand, Enter / Space to select, ARIA roles and names, a polite live region for counts, and a visible focus ring. When the user prefers reduced motion, animations snap to their end state instead of playing.

Requirements

  • React 18 or 19
  • GSAP 3.12+ (peer dependency)
  • A browser with WebGL for <BackgroundShader> (it degrades gracefully otherwise)

License

MIT © Francisco Piaggio. Built with GSAP.