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

mania-image

v0.1.1

Published

A TypeScript library for rendering osu!mania beatmaps to PNG images with Canvas 2D API.

Readme

mania-image

A TypeScript library for rendering osu!mania beatmaps to PNG images using Canvas 2D API.

Features

  • Canvas-based rendering — draws directly to Canvas 2D, no DOM overhead
  • Dual environment — works in browser (OffscreenCanvas) and Node.js (@napi-rs/canvas)
  • Vertical strip layout — splits long timelines into side-by-side strips
  • Customizable — notes, barlines, axis labels, colors, and layout modes are all configurable

Installation

pnpm add mania-image

Usage

Browser

import { render, type Beatmap } from 'mania-image'

const beatmap: Beatmap = { keys, notes, timingPoints }
const blob = await render(beatmap, {
  layout: { mode: 'size', size: [800, 600] },
})
// blob → <img> src or file download

Node.js

import { render } from 'mania-image/node'
import { createCanvas } from '@napi-rs/canvas'

const { canvas } = render(beatmap, (w, h) => {
  const c = createCanvas(w, h)
  return { canvas: c, ctx: c.getContext('2d')! }
}, opts)

canvas.toBuffer('image/png') // → Buffer

Note: This package does not include .osu file parsing. You can use osu-mania-io or osu-parsers to parse beatmaps, then pass the data to render().

Layout Modes

| Mode | Description | |------|-------------| | num | Split timeline into a fixed number of strips | | time | Split timeline into strips of fixed duration (ms) | | ratio | Auto-calculate strip count to match a target aspect ratio | | size | Auto-calculate to fit an exact output size (e.g. [800, 600]) |

Options

const defaultOptions = {
  note: {
    /** Width of each column in px */
    width: 20,
    /** Height of regular notes in px */
    height: 6,
    /** Corner radius in px */
    rx: 2,
    /** Width of long note body in px */
    bodyWidth: 10,
    color: {
      head: {
        schemes: { a: '#FFFFFF', b: '#5EAEFF', c: '#FFEC5E', d: '#FF3F00' },
        layouts: { /* key count → color scheme mapping */ },
      },
      body: '#CCCCCC',
    },
  },
  barline: {
    /** Stroke width of bar lines in px */
    strokeWidth: 1,
    color: '#85F000',
  },
  axis: {
    /** Width of the axis area in px */
    width: 30,
    fontFamily: 'Segoe UI, system-ui, sans-serif',
    minute: { color: '#FF3F00', strokeWidth: 2, fontSize: 18 },
    second: { color: '#FFFFFF', strokeWidth: 1, fontSize: 18 },
  },
  time: {
    /** Start time in ms ('auto' = first note) */
    start: 'auto' as 'auto' | number,
    /** End time in ms ('auto' = last note) */
    end: 'auto' as 'auto' | number,
    /** Vertical scale: px per ms */
    scale: 0.1,
  },
  layout: {
    /** Margin around strips in px */
    margin: 10,
    background: { color: '#000000' },
    mode: 'time',
    time: 15000,
  },
  renderer: {
    devicePixelRatio: 1,
  },
}

Exports

| Path | Environment | Entry | |------|-------------|-------| | mania-image | Browser | OffscreenCanvasBlob via convertToBlob | | mania-image/node | Node.js | External canvas factory → raw canvas |

License

MIT