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

@r2o3/rgchart-browser

v0.0.11

Published

A library for parsing and writing rhythm game charts.

Readme

rgchart

A library for parsing and writing charts for various rhythm games. It supports cross-platform usage including Web and Node.js environments via WebAssembly (WASM).

Table of Contents

Rust Usage

Installation

Add this to your Cargo.toml:

[dependencies]
rgchart = "0.0.11"

Or run:

cargo add rgchart

API Reference

Parsing Charts

use rgchart::parse;

// Parse an osu! chart from string to a generic mania chart
let osu_chart = parse::from_osu_generic(raw_osu_string).expect("Failed to parse osu! chart");

// Parse a Stepmania chart from string to a generic mania chart
let sm_chart = parse::from_sm_generic(raw_sm_string).expect("Failed to parse Stepmania chart");

// Parse a Quaver chart from string to a generic mania chart
let qua_chart = parse::from_qua_generic(raw_qua_string).expect("Failed to parse Quaver chart");

// Parse a fluXis chart from string to a generic mania chart
let fsc_chart = parse::from_fsc_generic(raw_qua_string).expect("Failed to parse fluXis chart");

to parse charts in their original structures:

use rgchart::FscFile;
use rgchart::OsuFile;
use rgchart::QuaFile;

// Parse an osu! chart from string
let osu_chart = OsuFile::from_str(raw_osu_string).expect("Failed to parse osu! chart");

// Parse a Quaver chart from string
let qua_chart = QuaFile::from_str(raw_qua_string).expect("Failed to parse Quaver chart");

// Parse a fluXis chart from string
let fsc_chart = FscFile::from_str(raw_fsc_string).expect("Failed to parse fluXis chart");

Writing Charts

use rgchart::parse;
use rgchart::write;
use rgchart::GenericManiaChart;

let chart: GenericManiaChart = parse::from_osu_generic(raw_osu_string).expect("Failed to parse osu! chart");

// Write from generic mania chart to to osu! format
let osu_string = write::to_osu_generic(&chart);

// Write from generic mania chart to Stepmania format
let sm_string = write::to_sm_generic(&chart);

// Write from generic mania chart to Quaver format
let qua_string = write::to_qua_generic(&chart);

// Write from generic mania chart to fluXis format
let fsc_string = write::To_fsc_generic(&chart);

to write charts from their original structures:

use rgchart::FscFile;
use rgchart::OsuFile;
use rgchart::QuaFile;

// Write from OsuFile to to osu! format
let osu_string = osu_chart.to_osu_format_mania(soundbank);

// assuming you don't have a soundbank
let osu_string = osu_chart.to_osu_format_mania_no_soundbank();

// other modes for osu!, it will interprete the hit objects values as is for the mode you're writing to.
let osu_string = osu_chart.to_osu_format();
// or
let osu_string = osu_chart.to_osu_format_standard(soundbank);

let osu_string = osu_chart.to_osu_format_taiko(soundbank);
let osu_string = osu_chart.to_osu_format_catch(soundbank);

// Write from QuaFile to Quaver format
let qua_string = qua_chart.to_str().expect("Failed to write Quaver chart");

// Write from FscFile to fluXis format
let fsc_string = fsc_chart.to_str().expect("Failed to write fluXis chart");

as of now you can't parse/write Sm files in their original structures.

Generic Mania Chart Structure

The GenericManiaChart contains all the relevant chart information:

pub struct GenericManiaChart {
    pub metadata: Metadata,
    pub chartinfo: ChartInfo,
    pub timing_points: TimingPoints,
    pub hitobjects: HitObjects,
    pub soundbank: Option<SoundBank>,
}

The Metadata contains all the metadata related information about a specific chart, a lot of all of these can be empty:

pub struct Metadata {
    pub title: String,
    pub alt_title: String,
    pub artist: String,
    pub alt_artist: String,
    pub creator: String,
    pub genre: String,
    pub tags: Vec<String>,
    pub source: String,
}

The ChartInfo contains all the gameplay information about a specific chart:

pub struct ChartInfo {
    pub difficulty_name: String,
    pub od: f32,
    pub hp: f32,
    pub bg_path: String,
    pub video_path: String,
    pub song_path: String,
    pub audio_offset: i32,
    pub preview_time: i32,
    pub key_count: u8,
}

The TimingPoints contains all the timing information such as bpm changes and sv:

pub enum TimingChangeType {
    Bpm,
    Sv,
    Stop
}

pub struct TimingChange {
    pub change_type: TimingChangeType,
    pub value: f32,
}

pub struct TimingPoint {
    pub time: i32,
    pub beat: f32,
    pub change: TimingChange,
}

pub struct TimingPoints {
    pub points: Vec<TimingPoint>,
}

The HitObjects struct contains all the hitobject information:

pub struct HitObject {
    pub time: i32,
    pub beat: f32,
    pub keysound: KeySound,
    pub key: Key,
    pub lane: u8,
}

pub struct HitObjects {
    pub objects: Vec<HitObject>,
}

Here is how sounds are handled for Mania. SoundBank contains all the sounds effects as well as a lookup for samples, it's done this way to be compatible with Quaver.

pub enum HitSoundType {
    Normal,
    Clap,
    Whistle,
    Finish,
}

pub struct SoundEffect {
    pub time: i32,
    pub volume: u8,
    pub sample: usize,
}
pub struct KeySound {
    pub volume: u8,
    pub hitsound_type: HitSoundType,
    pub sample: Option<usize>,
    pub has_custom: bool,
}

pub struct SoundBank {
    pub audio_tracks: Vec<String>,
    sound_sample_paths: Vec<String>,
    pub sound_effects: Vec<SoundEffect>,
    sample_map: HashMap<String, usize>,
}

JavaScript/TypeScript Usage

Installation

For Node.js:

npm install @r2o3/rgchart-nodejs

For web projects:

<script src="https://unpkg.com/@r2o3/rgchart-browser@latest/rgchart.js"></script>

or

npm install @r2o3/rgchart-browser

then use as an ES module

API Reference

Initialization

// For ES modules
import * as rgchart from '@r2o3/rgchart'; // or if not on node use the path to rgchart.js

// or alternatively
const rgchart = await import('path/to/rgchart.js')

// For CommonJS
const rgchart = require('rgchart');

you may need to do await rgchart.default() after importing if you've imported it in a script tag (with type="module") or you get an error like Uncaught TypeError: Cannot read properties of undefined (reading '__wbindgen_malloc')

As of now you can't parse/write using the original structures in JS/TS, will be supported in the near future.

Parsing Charts

// Parse an osu! chart from string to a generic mania chart
const OsuChart = rgchart.parseFromOsuGeneric(rawOsuString);

// Parse a Stepmania chart from string to a generic mania chart
const SmChart = rgchart.parseFromSmGeneric(rawSmString);

// Parse a Quaver chart from string to a generic mania chart
const QuaChart = rgchart.parseFromQuaGeneric(rawQuaString);

// Parse a fluXis chart from string to a generic mania chart
const FscChart = rgchart.parseFromFscGeneric(rawFscString);

Writing Charts

// write from generic mania chart to osu! format
const osuString = rgchart.writeToOsuGeneric(chart);

// write from generic mania chart to Stepmania format
const smString = rgchart.writeToSmGeneric(chart);

// write from generic mania chart to Quaver format
const quaString = rgchart.writeToQuaGeneric(chart);

// write from generic mania chart to fluXis format
const fscString = rgchart.writeToFscGeneric(chart);

TypeScript Types

The core chart library is written in Rust, but most types in the WASM bindings are generated for TypeScript.

See Chart Structure.

Building

Rust Library

cargo build

WASM Bindings

  1. Install wasm-pack:
cargo install wasm-pack

[!IMPORTANT]
It's really recommended to have wasm-opt installed and added to path for the wasm build.

  1. Build the package:
npm run build # debug build
npm run build-release # release build
  1. This will build it for both node and browser and the output will be in dist-web and dist-node directory.

License

RGC uses the MIT License for all its sibiling projects. See LICENSE for more information