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

@boxworld/miko

v0.1.2

Published

Embeddable pixel-sprite editor — palette + char-per-pixel frames, the miko sprite format used across the boxworld ecosystem

Readme

@boxworld/miko

An embeddable pixel-sprite editor for the miko sprite format — a palette plus char-per-pixel frame strings, the same shape used by the boxworld engine and the miko paint tool.

Zero runtime dependencies beyond React (a peer dependency). No backend, no storage, no opinions about your app — it reports every committed edit through onChange and lets you decide what that means.

Three ways in

The whole editor, one component:

import { Miko } from "@boxworld/miko";

<Miko value={sprite} onChange={(next) => save(next)} />;

Composed yourself, when you want your own layout, or only some of it:

import {
  MikoProvider, MikoCanvas, MikoToolbar, MikoPalette, MikoTimeline, MikoPreview,
} from "@boxworld/miko";

<MikoProvider value={sprite} onChange={save}>
  <header><MikoToolbar /><MikoPalette editable /></header>
  <main><MikoCanvas cellSize={24} /><MikoPreview size={128} /></main>
  <footer><MikoTimeline /></footer>
</MikoProvider>;

Headless, when you want none of the markup:

import { useMiko } from "@boxworld/miko";

const {
  sprite, cells, hash, frame, palette, color, tool, canUndo,
  startDrawing, draw, endDrawing, setColor, setTool,
  addFrame, deleteFrame, setFrame, reorderFrames,
  loadSprite, undo, redo,
} = useMiko({ value: sprite, onChange: save });

<Miko> is nothing but MikoProvider around a default arrangement of those same public components, so there is only ever one code path.

How state works

value is read once, on mount. It is deliberately not a controlled prop — a parent storing onChange's output back into it would fight the user's own edits. To open a different sprite, call loadSprite(next) (or remount with a key).

onChange fires when an edit is committed — the end of a brush stroke, a frame added, a colour changed — never mid-stroke. Read sprite from the hook if you need the in-progress state.

Two palettes are in play, and the distinction matters: colors is the set of paintable swatches (normalised so transparent and black are always present, padded to 10), while sprite.palette is the sprite's own encoding palette, holding only colours actually used in its frames and compacted by usage on every commit.

Undo

History is per-frame — switching frames clears it, which is what a frame-based animator expects. undo/redo step through it, and canUndo/canRedo say whether they'll do anything.

Theming

Everything renders with inline styles, so there is no stylesheet to import and none to fight. Colours come from CSS custom properties with sensible fallbacks:

:root {
  --miko-grid-line: #ccc;
  --miko-line: #999;
  --miko-selected: #333;
  --miko-active-bg: #eee;
  --miko-bg: #fff;
  --miko-text: #000;
  --miko-checker: #e8e8e8;
  --miko-font: 14px/1.4 system-ui, sans-serif;
}

Every component also takes className and style if you'd rather restyle them outright.

Pure helpers

floodFill, updateHash, optimiseFrames, normalisePalette, getHashArray, getDefaultHash, getRandomPalette and friends are exported as plain functions over a pixel hash string — no React involved — along with mikoReducer itself, if you want to drive the state machine your own way.

Develop

npm install
npm run typecheck
npm test
npm run build   # esbuild bundle + tsc declarations -> dist/

Note that react itself is deliberately absent from devDependencies — it is a peer dependency, and a second copy of the runtime breaks hook identity for the host app. The build marks it external and the tests are pure functions, so nothing here needs its own; npm installs the peer for you.

@types/react is a devDependency, because tsc cannot typecheck or emit declarations without it, but it is pinned to an exact version rather than a range. This package is developed inside the miko repo, and a different version here would put two React type identities in one program and break the host app's build. Keep the pin in step with the app's @types/react when either moves.