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

minimojs

v1.0.0-alpha.3

Published

MinimoJS v1 — ultra-minimal, flat, deterministic 2D web game engine. Emoji-only sprites, rAF loop, TypeScript-first, LLM-friendly.

Readme

MinimoJS v1

Ultra-minimal, flat, deterministic 2D web game engine.
Emoji-only sprites · Degrees rotation · Milliseconds timing · rAF loop · TypeScript-first · LLM-friendly


Install

npm install minimojs

Or build from source:

npm install
npm run build

Output: dist/minimo.js + dist/minimo.d.ts


Examples

  • examples/chickens-eggs-basket/ — Pollos lanzan huevos y una cesta los recoge.
  • examples/run-dino-run/ — Classic endless runner: jump with the dino and avoid obstacles.

Run examples from project root with a static server:

npx serve .

Open:

http://localhost:3000/examples/chickens-eggs-basket/

http://localhost:3000/examples/run-dino-run/


Quick Start

<script type="module">
  import { Game, Sprite } from "./dist/minimo.js";

  const game = new Game(800, 600);
  game.gravityY = 980;

  const player = new Sprite("🐢");
  player.x = 400;
  player.y = 300;
  player.size = 48;
  player.gravityScale = 1;
  game.add(player);

  game.onUpdate = (dt) => {
    if (game.isKeyDown("ArrowLeft"))  player.vx = -200;
    else if (game.isKeyDown("ArrowRight")) player.vx =  200;
    else player.vx = 0;

    if (game.isKeyPressed(" ") && player.y >= 550) player.vy = -600;

    if (player.y > 700) game.reset();

    game.drawText(`x: ${Math.round(player.x)}`, 10, 10, 16, "#ffffff");
  };

  game.start();
</script>

Core Rules

| Rule | Value | |---|---| | All time parameters | milliseconds | | All rotations | degrees | | Game loop | requestAnimationFrame only | | Sprites | emoji only | | Canvas layout | auto-centered + responsive scaling | | Coordinate system | center-based world space | | Y-axis | positive = down |


API Reference

new Game(width?, height?)

Creates the engine, creates its own canvas, and appends it to the page. Canvas is automatically centered and scaled to the maximum viewport space while keeping aspect ratio.

const game = new Game(800, 600);

Sprite Management

| Method | Description | |---|---| | game.add(sprite) | Register a Sprite instance with the engine and return it | | game.destroySprite(sprite) | Remove a sprite from the engine | | game.getSprites() | Read-only snapshot of all sprites |

Creating sprites — instantiate Sprite directly or subclass it:

// Plain instantiation
const coin = new Sprite("🪙");
coin.x = 300; coin.y = 200; coin.size = 32;
game.add(coin);

// Subclassing
class Enemy extends Sprite {
  health = 3;
  constructor(x: number, y: number) {
    super("👾");
    this.x = x; this.y = y; this.size = 40; this.gravityScale = 1;
  }
}
const enemy = game.add(new Enemy(600, 100));

Sprite properties and defaults:

| Property | Type | Default | Description | |---|---|---|---| | sprite | string | — | Required in constructor. Single emoji | | x | number | 0 | World X (center), pixels | | y | number | 0 | World Y (center), pixels | | size | number | 32 | Bounding square size, pixels | | rotation | number | 0 | Degrees, clockwise | | flipX | boolean | false | Visual horizontal mirror | | flipY | boolean | false | Visual vertical mirror | | ignoreScroll | boolean | false | Render in screen space (ignore scrollX/scrollY) | | alpha | number | 1 | Opacity 0–1 | | visible | boolean | true | Render toggle | | layer | number | 0 | Render order (higher = on top) | | vx | number | 0 | Horizontal velocity, px/s | | vy | number | 0 | Vertical velocity, px/s | | gravityScale | number | 0 | Gravity multiplier |


Public State

| Property | Type | Description | |---|---|---| | game.gravityX | number | Horizontal gravity acceleration, px/s² | | game.gravityY | number | Vertical gravity acceleration, px/s² | | game.scrollX | number | Camera scroll X offset, pixels | | game.scrollY | number | Camera scroll Y offset, pixels | | game.background | string \| null | Solid canvas background color | | game.backgroundGradient | { from: string; to: string } \| null | Vertical canvas gradient (from top, to bottom) | | game.pageBackground | string \| null | Full page (document.body) background color | | game.pointerX | number | Pointer X in screen space, pixels (read-only) | | game.pointerY | number | Pointer Y in screen space, pixels (read-only) | | game.width | number | Canvas width, pixels (read-only) | | game.height | number | Canvas height, pixels (read-only) | | game.onCreate | () => void | Scene creation callback (start + reset) | | game.onUpdate | (dt: number) => void | Frame callback. dt = seconds |


Background

game.background = "#92d7ff";      // solid canvas background
game.backgroundGradient = { from: "#92d7ff", to: "#5ca44f" }; // vertical gradient
game.pageBackground = "#f4e4bc";  // page background
// If backgroundGradient is set, it takes priority over background.

Collision (AABB, no resolution)

game.overlap(a, b)               // → boolean
game.overlapAny(listA, listB)    // → [Sprite, Sprite] | null

Bounding box is a square centered at (x, y) with side size. Rotation ignored.


Input

// Keyboard
game.isKeyDown("ArrowRight")   // true every frame while held
game.isKeyPressed("ArrowRight") // true only on first frame of press

// Pointer (mouse / touch)
game.isPointerDown()   // true every frame while held
game.isPointerPressed() // true only on first frame of press
game.pointerX          // screen space X
game.pointerY          // screen space Y

Sound

game.sound(freq, durationMs)
// Square wave only. freq in Hz. durationMs in milliseconds.
game.sound(440, 100);  // 440 Hz beep for 100ms

Animation

game.animateAlpha(sprite, to, durationMs, onComplete?)
game.animateRotation(sprite, toDegrees, durationMs, onComplete?)
// Linear interpolation. durationMs in milliseconds.
// New animation on same property replaces the current one immediately.

Timers

const id = game.addTimer(delayMs, repeat, callback)
game.clearTimer(id)
// rAF-driven (no setTimeout). delayMs in milliseconds.
// repeat=true fires every delayMs; repeat=false fires once then removes.
// All timers cleared on game.reset().

Text Overlay

game.drawText(text, x, y, fontSize, color?, centered?)
// Screen space (ignores scroll). Must be called every frame.
// Always renders on top of all sprites.
// Font is always monospace (fixed by engine).
// Default color: "#ffffff"
// centered=true makes (x, y) the center anchor (both axes).

Misc

game.isMobileDevice() // true on likely mobile/touch-first devices (heuristic)
game.random()  // Math.random() wrapper → [0, 1)
game.reset()   // Full state clear + calls onCreate() for scene rebuild
game.start()   // Start rAF loop
game.stop()    // Stop rAF loop

Scene Creation and Reset

MinimoJS has no scene system. Use onCreate() to build scenes and reset() to rebuild:

game.onCreate = () => {
  // Scene init — called on start and after reset()
  const skull = new Sprite("💀");
  skull.x = 400; skull.y = 300; skull.size = 96;
  game.add(skull);
};

function goToGameOver() {
  game.reset(); // clears everything, calls onCreate()
}

Forbidden Features

These do not exist in MinimoJS v1:

  • Scene system / scene manager
  • Entity Component System (ECS)
  • Physics engine
  • Camera zoom
  • Nested APIs
  • Text input
  • Parallax
  • Multiple cameras
  • Collision resolution
  • Image sprites (PNG/SVG)
  • setTimeout / setInterval

Build

npm run build    # compile to dist/
npm run clean    # remove dist/
npm run rebuild  # clean + build
npm run pack:check # preview npm package contents

TypeScript target: ES2020, module: ES2020, strict mode, declaration files enabled.


NPM Publish Notes

  • prepack runs npm run build automatically before packaging.
  • files whitelist includes only:
    • dist/
    • README.md
    • LICENSE
  • Example code under examples/ is for repository usage and is excluded from the npm package.

License

MIT