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

automatick

v0.0.2

Published

State-machine engine for tick-based simulations in React

Readme

automatick

State-machine engine for tick-based simulations in React. You write the rules (init, step, params); automatick handles the loop, timing, status state machine, controls, and (optionally) running the simulation in a Web Worker.

Install

npm install automatick

React is an optional peer dependency — the engine has no React surface.

Quick start

A simulation has three parts: a sim module (pure logic), a <Simulation> wrapper, and a render component reading state via useSimulation().

// counterSim.ts
import { defineSim } from 'automatick/sim';

export default defineSim<{ count: number }, { increment: number }>({
  defaultParams: { increment: 1 },
  init: () => ({ count: 0 }),
  step: ({ data, params }) => ({ count: data.count + params.increment }),
});
// Counter.tsx
import { Simulation } from 'automatick/react/simulation';
import { useSimulation } from 'automatick/react/hooks';
import { StandardControls } from 'automatick/react/controls';
import counterSim from './counterSim';

function Display() {
  const { data, tick } = useSimulation<typeof counterSim>();
  return <p>Tick {tick}: count is {data.count}</p>;
}

export default function Counter() {
  return (
    <Simulation sim={counterSim}>
      <Display />
      <StandardControls />
    </Simulation>
  );
}

StandardControls gives you play/pause, reset, step, seek, and parameter inputs out of the box. For finer control, individual primitives live at automatick/react/control-primitives.

Web worker

Same sim module, one prop change — the simulation now runs off the main thread:

<Simulation worker={() => import('./counterSim')}>
  <Display />
  <StandardControls />
</Simulation>

Useful when step is expensive (large grids, n-body simulations, fluid solvers) and you want the UI to stay responsive.

API at a glance

defineSim<Data, Params>({ init, step, shouldStop?, defaultParams }) declares a sim module.

step receives { data, params, tick } and returns the next Data.

shouldStop(data, params) => boolean is an optional terminal predicate; the engine moves to 'stopped' when it returns true.

useSimulation<typeof sim>() returns the current snapshot and actions:

| Field | Type | Description | |---|---|---| | data | Data | Current simulation state | | params | Params | Current parameters | | tick | number | Current tick (starts at 0) | | status | 'idle' \| 'playing' \| 'paused' \| 'stopped' | Engine status | | play(), pause(), stop() | () => void | Lifecycle controls | | seek(tick) | (n: number) => void | Jump forward; pauses | | advance(n?) | (n?: number) => void | Step forward by n ticks (default 1) | | setParams(patch) | (patch: Partial<Params>) => void | Update params without reinit | | resetWith(patch?) | (patch?: Partial<Params>) => void | Re-run init with optional param patch |

Package entry points

| Subpath | Exports | |---|---| | automatick | createEngine, engine + status types | | automatick/sim | defineSim, SimModule, SimData, SimParams | | automatick/worker/runner | Worker-side runtime | | automatick/worker/create | Worker host factory | | automatick/worker/protocol | Message protocol types | | automatick/react/simulation | <Simulation> | | automatick/react/hooks | useSimulation() | | automatick/react/controls | <StandardControls> | | automatick/react/control-primitives | Individual UI primitives | | automatick/react/canvas | useSimulationCanvas() | | automatick/react/performance | <PerformanceOverlay> | | automatick/react/context | <SimulationContext> |

All entry points use named exports. If you'd rather have a single namespace object, use import * as Automatick from 'automatick' and call Automatick.createEngine(...) — same for any subpath.

License

MIT