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

@wasm-gaming/rom-manager

v0.1.8

Published

Embeddable ROM metadata editor - like mp3tag for video game ROMs

Readme

ROM Manager

A client-side tool (no backend) for managing a retro ROM collection: it groups files by game with their different variants (region, revision, language), and attaches metadata and cover art to them.

Files are accessed through the File System Access API, so nothing is ever uploaded anywhere. Real support only exists in Chromium browsers.

Project Specs

Goal

  • The heart of the project is the dataset: a catalog of games with their variants, generated by hash matching against DATs (No-Intro / Redump).
  • Target: retro games. The catalog is practically static — retro-system DATs are already mature — so no architecture for full dataset regeneration is needed; it can grow incrementally.
  • The manager identifies ROMs by hash, never by file name. A local name is not trustworthy; a CRC32 checked against the DAT is.

How it works

  • 24 mainstream MiSTer systems, identified by the exact folder name MiSTer uses under /games. Each declares a fixed medium: cartridge or disc. Neo Geo is the one whose games also arrive as a romset — a folder or zip of chip dumps, identified by the checksums of its members rather than by one of its own. See Target systems.
  • Grouping by base title. Every DAT entry is a candidate variant; the region, language, revision and flag tags in its name produce a variant key, and normalizeGameName() produces the group key that names the folder and resolves the cover. See Grouping.
  • Folder structure depends on the medium: cartridge systems are flat (<system>/<Game>.<variant>.<ext>), disc systems get a folder per game and a subfolder per variant. Metadata always lives outside the ROM folders, in .meta/. See Folder structure and canonical organization.
  • One cover per region (EU, US, JP), sourced from libretro-thumbnails and cached locally as you browse. A preference order decides which one is shown. See Cover art.
  • Curated collections are off limits. The manager only scans and organizes the base folder of each system, never the contents of a collection folder. See Collections.
  • The explorer has two modes: flat (the raw filesystem listing) and wizard (recognized files folded into their game, one row per game). See File explorer.

Folder structure at a glance

Nintendo - SNES/Super Mario World.USA.sfc
Nintendo - SNES/Super Mario World.Japan-rev1.sfc

Sony - PlayStation/Final Fantasy VII/game.json
Sony - PlayStation/Final Fantasy VII/USA/Final Fantasy VII (USA) (Disc 1).bin
Sony - PlayStation/Final Fantasy VII/USA/Final Fantasy VII (USA) (Disc 1).cue

.meta/<system>/<Game>.json                       # editable metadata
.meta/<system>/<Game>.<region>.case.png          # cover for one region
.meta/<system>/scan.json                         # hash cache
.meta/wizard.json                                # per-folder settings

Design principles to preserve

  • The canonical dataset is the source of truth for grouping; it is queried while browsing, never rewritten on the fly.
  • The manager never touches anything inside a collection folder.
  • Every per-folder behavior decision (wizard on/off) is explicit and persisted (wizard.json), never inferred by heuristic.
  • Anything that moves the user's files is split in two: a plan, which touches nothing, and its application, which never happens without the plan having been shown first.

Documentation

| Document | Contents | |---|---| | docs/systems.md | The closed list of supported systems, their medium and their DAT, and how Neo Geo romsets are identified by their members. | | docs/grouping.md | Game ↔ variant grouping, variant identity, regions and video standards, name normalization. | | docs/folder-structure.md | On-disk layout per medium, the .meta/ layer, and the canonical organization operation with its undo log. | | docs/covers.md | One cover per region: how they are matched, chosen, downloaded and stored, plus hand-added images. | | docs/collections.md | What a collection is and why the manager stays out of it. | | docs/explorer.md | Flat mode vs wizard mode, one row per game, region preference order, drag and drop. |

Sessions and specifications live in SESSIONS/; see AGENTS.md for the working conventions.

Development

Requires Node >= 24.

npm install
npm run dev          # dev server
npm run build        # app build
npm run build:lib    # embeddable library build
npm run test         # vitest
npm run type-check   # tsc --noEmit

Dataset generation (network access required):

npm run dataset:fetch-dat      # download the DATs from libretro-database
npm run dataset:fetch-covers   # list the libretro-thumbnails repositories
npm run dataset:to-json        # build static/datasets/ from what is downloaded

Every dataset is regenerable from those three commands alone; nothing in static/datasets/ is hand-made. A generated dataset can then be checked against a real collection of ROMs, which reads no file name and decompresses nothing:

npm run dataset:verify-romsets -- <folder> --system=NEOGEO

Todos

  • Editable per-game metadata: today the .json record is indexed by the file path, so in the canonical cartridge structure it ends up being per variant (<Game>.<variant>.json) instead of per game, which is what the design calls for.
  • Neo Geo romsets in the browser: the dataset already carries the members' checksums, but the app does not read them yet — identifying a zip as a set, taking one in whole instead of unpacking it, and naming a Neo Geo file after its romset are still to be written. See docs/systems.md.