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

@tdreyno/fizz

v8.11.1

Published

[![npm latest version](https://img.shields.io/npm/v/@tdreyno/fizz/latest.svg)](https://www.npmjs.com/package/@tdreyno/fizz)

Downloads

1,898

Readme

Fizz

npm latest version

Fizz is a small library for building state machines that can effectively manage complex sequences of events. Learn more about state machines (and charts).

Fizz works well across a spectrum:

  • small, component-local workflows such as toggles, editors, and async button states
  • larger orchestration flows with timers, parallel branches, nested machines, and long-running effects

Install

npm install --save @tdreyno/fizz

Start with the main docs Getting Started page for a minimal setup and runtime demo. For adapter-facing command workflows, see Output Actions, including commandChannel(...) for channel-bound command and batch ergonomics.

A small component-local example

This is a tiny local workflow: a button that starts idle, enters a saving state, then reports done.

import {
  ActionCreatorType,
  Enter,
  action,
  createMachine,
  state,
} from "@tdreyno/fizz"

const save = action("Save")
type Save = ActionCreatorType<typeof save>

type Data = {
  status: "idle" | "saving" | "done"
}

const Idle = state<Enter | Save, Data>({
  Enter: (data, _, { update }) => update(data),
  Save: data => Saving(data),
})

const Saving = state<Enter, Data>({
  Enter: (data, _, { update }) =>
    update({
      ...data,
      status: "done",
    }),
})

const SaveButtonMachine = createMachine(
  {
    actions: { save },
    states: { Idle, Saving },
  },
  "SaveButtonMachine",
)

When this shape grows beyond one local workflow, Fizz can scale to nested and parallel orchestration patterns without changing the core model.

Complex orchestration example: let's play pong

This example shows how we would model something like a game of Pong.

import {
  state,
  action,
  ActionCreatorType,
  onFrame,
  OnFrame,
  Enter,
} from "@tdreyno/fizz"

export const start = action("Start")
export type Start = ActionCreatorType<typeof start>

export const onPaddleInput = action("OnPaddleInput")
export type OnPaddleInput = ActionCreatorType<typeof onPaddleInput>

type Data = {
  ballPosition: [x: number, y: number]
  ballVector: [x: number, y: number]
  leftPaddle: number
  rightPaddle: number
}

const Welcome = state<Start, Data>({
  Start: () =>
    Playing({
      ballPosition: [0, 0],
      ballVector: [1, 1],
      leftPaddle: 0,
      rightPaddle: 0,
    }),
})

const Playing = state<Enter | OnPaddleInput | OnFrame, Data>({
  Enter: onFrame,

  OnPaddleInput: (data, { whichPaddle, direction }, { update }) => {
    data[whichPaddle] = data[whichPaddle] + direction

    return update(data)
  },

  OnFrame: (data, _, { update }) => {
    // Handle bouncing off things.
    if (doesIntersectPaddle(data) || doesTopOrBottom(data)) {
      data.ballVector = [data.ballVector[0] * -1, data.ballVector[1] * -1]

      return [update(data), onFrame()]
    }

    // Handle scoring
    if (isOffscreen(data)) {
      return Victory(ballPosition < 0 ? "Left" : "Right")
    }

    // Otherwise run physics
    data.ballPosition = [
      data.ballPosition[0] + data.ballVector[0],
      data.ballPosition[1] + data.ballVector[1],
    ]

    return [update(data), onFrame()]
  },
})

const Victory = state<Enter, string>({
  Enter: winner => log(`Winner is ${winner}`),
})

onFrame is an action that is called via requestAnimationFrame. Assume doesIntersectPaddle, doesTopOrBottom and isOffscreen are doing bounding boxes checks.

Our renderer can now check the current state each frame and decide whether to render the Welcome screen, the Victory screen or the game of Pong.