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

yuuna-engine

v0.7.0

Published

A lightweight, state-machine-based TypeScript game engine for quick prototypes. Runs directly in the browser.

Readme

Yuuna

Live demo & playground · GitHub

A lightweight, state-machine-based TypeScript game engine — drop it into a page and it's running, no editor or build step required. You describe your game as a state, a render(state) function, and a nextState({ state, event, keyboard }) function — Yuuna owns the render loop, input handling, and canvas drawing.

Install

npm install yuuna-engine

Quick start

Add a canvas with id="yuuna" to your page:

<canvas id="yuuna"></canvas>

Then describe your game as state + render + nextState:

import { runEngine } from "yuuna-engine";

// The shape of your game's data — whatever it takes to fully describe
// what's on screen and how it behaves
type GameState = { cookies: number };

// What that state looks like before anything has happened yet
const initialState: GameState = { cookies: 0 };

runEngine<GameState>({
  initialState,

  // Given the current state, what should be drawn this frame? Called
  // every frame — always derive the picture from state, instead of
  // reaching for the canvas directly.
  render: (state) => ({
    renderables: [
      {
        type: "TEXT",
        text: `${state.cookies} cookies`,
        color: "black",
        position: { x: 100, y: 50 },
      },
      {
        type: "CIRCLE",
        id: "cookie",
        isClickable: true,
        color: "brown",
        position: { x: 50, y: 50 },
        radius: 25,
      },
    ],
  }),

  // Given the current state and something that just happened, what's the
  // next state? Called once per event (a click, a frame tick, ...) — the
  // only place game logic lives.
  nextState: ({ state, event }) => {
    if (event.tag === "CLICK" && event.id === "cookie") {
      return { cookies: state.cookies + 1 };
    }

    return state;
  },
});

Concepts

  • Renderables — declarative shapes drawn each frame: RECTANGLE, CIRCLE, TEXT, SPRITE, ANIMATED_SPRITE, LINE, and GROUP. Give one an id plus isClickable/isHoverable to make it interactive.
  • EventsnextState receives one GameEvent per call: TIME, CLICK, HOVER_IN, HOVER_OUT, MOUSE_MOVE, MOUSE_LEAVE, MUSIC_END, or a CUSTOM event of a type you define yourself, for reporting things like an async fetch() resolving back into your state machine.
  • Keyboard, camera, sprites & animation, sound effects & music, canvas config, and mechanics pipelines all follow the same idea: small, focused props and functions runEngine/nextState take, that compose with everything above instead of replacing it.

This README stays intentionally thin — the full concept-by-concept reference, with every option and example, lives on the wiki. The playground also has a small, focused example for most of these you can run and edit directly.

Templates

Prefer a working starting point over typing the quick start out by hand? Grab one from templates/:

  • blank — a single index.html, zero install — open it in a browser and it runs.
  • npm — TypeScript + a dev server with hot reload (via Vite), for a real local project.
  • neutralino-desktop — the npm template wrapped in Neutralino to run as a native desktop window.
npx degit lucy-dot-exe/yuuna/templates/blank my-game
# or: npx degit lucy-dot-exe/yuuna/templates/npm my-game
# or: npx degit lucy-dot-exe/yuuna/templates/neutralino-desktop my-game

degit copies the folder without its git history — no cloning or forking the whole engine repo needed. Each template's own README has more on running it once copied.

Made with Yuuna

Development

yarn install
yarn build   # builds lib/ (npm package) and dist/bundle.js (landing page)
yarn watch   # rebuild on change

dist/index.html is the landing page — it loads dist/bundle.js in the browser via a global Yuuna object and embeds a live Monaco editor so visitors can edit and run a game directly on the page.

Assets

The examples' art/sound/music lives in dist/resources/, gitignored rather than committed — this repo being open source doesn't make every asset in it free to redistribute. runEngine() falls back to a generated placeholder for any image that isn't there (and simply plays nothing for missing audio) instead of failing, so the examples still run without them — just with placeholder art in place of the real thing. Drop the real files in locally (or restore them from wherever you got this repo from) to see them for real.

Currently used:

License

MIT © lucy-dot-exe