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

@onceworlds/cli

v0.14.0

Published

Deploy games to Onceworlds.

Readme

@onceworlds/cli

Publishes browser games to Onceworlds, where every game gets multiplayer, saves, player accounts and a shared overlay (sound, chat, players) with no server code.

Deploy from GitHub Actions

Deploys run from GitHub Actions: GitHub vouches for the repo, so there are no API keys. The easiest setup is to import the repo at https://onceworlds.com/upload?new=github, which adds onceworlds.json and .github/workflows/onceworlds.yml for you (that workflow also builds with npm, pnpm, yarn or bun when there's a build script). To write the same files into a folder before it is on GitHub, run npx @onceworlds/cli init there. By hand, the minimum is:

name: Deploy to Onceworlds
on:
  push:
    branches: ['**']
permissions:
  contents: read
  id-token: write # proves which repo is deploying; no API keys needed
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
      - run: npx --yes @onceworlds/cli@latest deploy

Pushes to the production branch (main unless you change it in the dashboard or onceworlds.json) go live at onceworlds.com/play/<slug>; other branches get a preview URL in the job log. Log in to https://onceworlds.com with a GitHub account that has write access to the repo before the first deploy. Install the Onceworlds GitHub App on that repo to use the dashboard and open the game while private. If a deploy fails, the dashboard shows why.

New games start private: only accounts with write access to the repo can play them. To share one, open it in the dashboard and pick Unlisted (anyone with the link) or Public (also listed on Onceworlds).

Project file

onceworlds.json at the root of the repo:

{
  "slug": "kart-rush",
  "name": "Kart Rush",
  "description": "Race friends around twisty tracks.",
  "dir": ".",
  "genre": "Racing",
  "icon": "store/icon.png",
  "thumbnails": ["store/thumb-1.png", "store/thumb-2.png"],
  "badges": [{ "id": "first-win", "name": "Top Step", "description": "Win a race." }]
}

engine ("1", "1.2" or an exact "1.2.3") makes a game run on the engine the platform hosts: it adds an import map so import { createGame } from '@onceworlds/engine' works in a page with no build step. "1" is the newest 1.x, which gets fixes without a redeploy; an exact version never changes. A deploy fails, saying what is available, for a version that doesn't exist.

dir is the folder to publish (for example dist after a build); it must contain index.html. productionBranch (default main) picks the branch that goes live; the dashboard can change it too, and the file wins again only when this value changes.

controls ([{ "keys": ["W", "A", "S", "D"], "action": "Move" }], up to 12) fill "How to play" in the platform menu, folded until a player opens it (help is still accepted but no longer shown). The rest fills in the game page: genre, a square icon (at least 128×128), 16:9 thumbnails (at least 480 wide; the first is the cover) and badges (id, name, description and an optional square icon). A game page holds at most 5 thumbnails and videos together, and a game at most 50 badges. Images are PNG, JPEG, WebP or GIF up to 5 MB, with paths relative to onceworlds.json. Live deploys apply these fields only when they change, so edits made in the dashboard last until then.

Make the art before the first deploy: players see the icon and thumbnails before the game, and a game without them gets a plain colored placeholder. The icon is a simple, wordless 512×512 square; the thumbnails are three to five 1280×720 pictures of the game being played, the best one first (it is the cover). Capture them from the running game and commit them under store/. onceworlds doctor says which fields are missing.

Commands

  • onceworlds new [folder] starts a game on the web platform and the SDK: index.html, game.js on the stack you pick (--stack canvas, the default with no library, three, pixi or phaser, loaded from a CDN by an import map), rules.js with tests that run in Node (npm test: node --test, nothing to install), an onceworlds.json for your game (--name, --slug, --description; the folder's name by default), the platform guide as AGENTS.md and CLAUDE.md, a DESIGN.md to fill in first (the hook and signature mechanic, an originality pass, the first minute, playing together, the art direction, the feel, the UI, the stack and a pre-build check), a .gitignore and the deploy workflow. Each starting point is tiny on purpose: the platform wired in (a room joined as the page loads, you and everyone in your server, the keys and the phone's thumbstick, a title with one Play button) and nothing that decides the game. --engine makes a blank project on the Onceworlds engine instead, an optional library (--space 3d for 3D), with the engine guide as its AGENTS.md. --kit <name> starts from an engine kit: a complete game of one kind (--list shows them), a reference for its plumbing (rooms, netcode, Flow, bots, tests) whose idea, look and screens are never yours; it adds its own notes as KIT.md and its fingerprints as .onceworlds/kit.json, so check can note what is still the kit's. --template party or starter starts from a complete game on the SDK, and --template <name> from a scene project of Onceworlds Build.

  • onceworlds check [dir] is what to run before a deploy, for any game (canvas, three.js, PixiJS, Phaser, the DOM, the engine, a Godot or Ren'Py web export): doctor's findings, plus the hosts the platform's CSP won't let the game reach, WebSockets of its own, text too small for a phone, a second countdown under the platform's lobby, shared state written from Math.random() or the device's clock, and a DESIGN.md silent on originality and the first minute. Then it plays the game on the local platform (serve's) in headless Chrome: it loads with no errors, draws, joins a room (pressing Play as a player does), starts its match from the platform's lobby, answers input, takes a second player, survives its host reloading and then leaving, fits a phone (nothing of its text under the platform's menu or touch controls, text big enough, no sideways scrolling), and keeps its own work per frame and its memory in hand: one ✓, ! or ✗ line each, with the fix. A ✗ exits with an error (--strict: a ! too); --quick skips the browser. For an engine game it also runs the game's own tests (npm test) and simulated matches played with no browser, with a reloaded host, a dropped player, the host changing (also while paused), a late joiner and garbage messages. A failing test or a match with errors exits with an error. The game's config is read from game.config.js (or src/game.config.js, or --config <file>): export const config = {...}, and export const actions lets check compare "How to play" with the action map exactly. Needs npm install in the game folder. Simulated players only ready up, so a game with long rounds or turn timers may not reach its results in the time check has: export const quick = ... from the same file (the game with one short round and short timers) and check plays that. A process that outlives its time limit is killed with everything it started.

  • onceworlds posters [dir] draws each game.poster() scene of your latest draft (?poster=<name>) in a browser on this computer and saves the pictures into store/ (a poster name is letters, digits, dashes, underscores and dots, as in the engine), naming them in onceworlds.json when it has no icon or thumbnails. --only cover,icon picks some.

  • onceworlds init [dir] sets a game folder up, with the files the dashboard's import commits. It writes onceworlds.json (the link and name come from package.json's name or the folder's; dir is your build's output folder when package.json has a build script, else . or the folder with your index.html), .github/workflows/onceworlds.yml, a .gitignore (node_modules/ and the pictures shot and shot --story save; to one you have it adds only those lines, once), and the guide for AI coding tools as AGENTS.md with a CLAUDE.md that imports it (next to a AGENTS.md of your own it writes ONCEWORLDS.md and adds a pointer to yours). It never overwrites a file you have: --force replaces only what init writes, never your own AGENTS.md, CLAUDE.md or .gitignore. onceworlds new writes the same workflow and .gitignore into every game it makes. Then commit, push, and import the repo at https://onceworlds.com/upload?new=github.

  • onceworlds deploy [dir] uploads only the files that changed and publishes the game (the workflow runs it). It lists every file it skipped because Onceworlds can't serve it. A game's tests never go up: *.test.js, vitest.config.* and the test/ folder at the top of the game.

  • onceworlds serve [dir] plays any game in your own browser on this computer, offline and with no login, on a local platform at http://127.0.0.1:8788/ (--port): the platform's play page (its bridge, room connection, lobby, touch controls and the corner the menu takes), its rooms (matchmaking, private servers with &server=<code>, the host role, held seats, state, private values, ready, the countdown and the match, as onceworlds.com runs them) and the real SDK with its helpers (/__onceworlds/v1/match.js, host.js, bots.js), under the platform's CSP. Saves, badges, leaderboards and game data ("data") are kept in memory while it runs. Each browser is a player, and ?player=2 to 9 are more in the same one. A game with a build script is built first and its dir served. Ranked ratings, parties into matchmaking, onceworlds.fetch and chat moderation need onceworlds.com. An engine game uses the installed engine (else the hosted copy this CLI ships with) and also gets its page on its own, the engine's stand-in for the platform, with --bots 3 (the default) bots; any other game gets ?bots=N passed on.

  • onceworlds dev [dir] deploys to a local Onceworlds platform (for platform development) and redeploys on every save. --players 3 also prints links for players 2 and 3 (?player=N): on a local platform each is another player, so one person can fill a lobby.

  • onceworlds doctor [dir] looks through the game's files for what games often ship with: no viewport tag, text fields under 16px (Safari zooms the page when one is focused), confirm() and other dialogs (blocked in the game frame), localStorage (gone on reload), and, for games with rooms, Date.now() for shared time and no use of the platform's lobby. For an engine game it also reads the action map and offers the controls it implies: --fix writes them into onceworlds.json when it has none. For an installed engine game the list is the engine's own (controlsFromActions on the actions that game.config.js exports); otherwise it is read from the source text (Input.axis2d, Input.button) and may differ. It checks onceworlds.json by every rule a deploy applies (lengths, genres, badges, How to play, the pictures it names), in the deploy's words and with the fix, and fails as the deploy would; the rest only suggests (--strict exits with an error on likely bugs, for CI). check does the same. For an engine game it also says when DESIGN.md is missing or has parts left empty (the originality pass included), and notes a game still close to the kit it started from (scripts unchanged, the kit's numbers, its screens). For a game on Flow it says what still looks like a kit (Flow's placeholder screens, the default theme), a 3-2-1 of the game's own beside Flow's, and a first round no different from the rest. Taste is the game's: these are warnings and notes, never a failure.

  • onceworlds api <name or words> looks the engine up in a few lines instead of the whole reference: a signature, what it does, a component's fields or an options object's keys, and an example (api Shape2D, api feel.shake, api "camera follow"; --full for every field with its doc). onceworlds recipe [name] prints short, tested code for a kind of game or a feature (tycoon, survival, racing, platformer, shooter, party, rpg, idle, sandbox, chase-ai, inventory, shop, dialogue, day-night), and onceworlds guide [topic] the engine guide's topics or any heading of the guide or the reference. They read the index of the engine installed in the game's node_modules (its own version), else the platform's.

  • onceworlds shot [dir] saves a picture of any game to look at: a moment of play (--at 20), the title screen (--phase title) or the lobby (--phase lobby), or a poster (--poster cover), at --size 1280x720 by default (--size all makes one each of 390x844, 844x390, 1280x720 and 1920x1080). A game off the engine is played on the local platform in Chrome: the title as it loads, the lobby once it joins (a Play button pressed when it waits on one), or play after the platform's Start (more local players join when its match needs them), moving about, with the platform's menu (and on a phone its touch controls) over it as players see it; the caption names errors, files the CSP refused, fonts that never loaded, symbols and text too small. A poster is the game's own ?poster= page when it says data-ready. An engine game in 2D is drawn with no browser, from the frame the engine draws, with its text in the fonts the game's files name (its own font files, or Google Fonts, downloaded once and kept) and Sora for the rest; the caption says which it couldn't have, and that the HTML overlay (ui.overlay) needs --browser. A 3D game (or --browser) is drawn by Chrome, Chromium or Edge from a local copy of the game. --out picks the file (default store/shot.png). --story plays the first minute as a new player lives it (the title, the lobby, the countdown, the round's goal, play at +1, +5 and +12 s, the first result), saves each frame into store/story/ and lays them out on one contact sheet, store/story.png, with the questions to ask of it.

Running onceworlds mcp gives an AI tool the same as tools: api_lookup, recipe, read_guide, search_assets (the engine's asset library), check, screenshot (the picture comes back to the model), serve (an address for the user to play it at), new_game, deploy_preview, playtest (local: true for the folder on the local platform) and game_status.

  • onceworlds playtest [dir] plays the game as several guests in headless Chrome (join, a match, reloads, drops, the host leaving, a late arrival, a phone): your latest draft, or --local the folder on the local platform, with no login.

Games talk to the platform through the injected window.onceworlds SDK. The starter template's AGENTS.md documents it for AI coding tools.