{"id":25039,"library":"bsmap","title":"bsmap - Beat Saber Beatmap Scripting Library","description":"bsmap is a general-purpose TypeScript library for creating, reading, and modifying Beat Saber beatmaps programmatically. Current stable version is 2.3.4. Maintained actively with frequent releases (every few months). It supports all major beatmap schema versions (v1 through v4.1.0) and modding extensions like Chroma, Cinema, Noodle Extensions, and Mapping Extensions out of the box. Key differentiators: fully-typed schema wrappers for cross-version compatibility, partial object creation with default filling, tree-shakeable modules, built-in validators and optimisers, and utilities for math, color, and easing. Works with Deno, Bun, Node.js (ESM/CJS), and browser bundlers.","status":"active","version":"2.3.4","language":"javascript","source_language":"en","source_url":"https://github.com/KivalEvan/BeatSaber-JSMap","tags":["javascript","beat","saber","beatsaber","beatmap","typescript"],"install":[{"cmd":"npm install bsmap","lang":"bash","label":"npm"},{"cmd":"yarn add bsmap","lang":"bash","label":"yarn"},{"cmd":"pnpm add bsmap","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Library requires TypeScript for type checking and development, though runtime can be any JS runtime.","package":"typescript","optional":true}],"imports":[{"note":"For ESM (Deno, Bun, Node with 'type':'module'). CJS users: use require('bsmap'). Default import (import bsmap from 'bsmap') is not available.","wrong":"const bsmap = require('bsmap')","symbol":"bsmap","correct":"import * as bsmap from 'bsmap'"},{"note":"Named export from the main package. There is no subpath export for io in v2+.","wrong":"import readDifficultyFileSync from 'bsmap/io'","symbol":"readDifficultyFileSync","correct":"import { readDifficultyFileSync } from 'bsmap'"},{"note":"Beats utility class is exported from a subpath 'bsmap/beats' since v2.0.0. Also available as named export from main, but subpath is preferred for tree-shaking.","wrong":"import { Beats } from 'bsmap'","symbol":"Beats","correct":"import { Beats } from 'bsmap/beats'"},{"note":"Wrapper class for difficulty beatmap data. Available directly from main import.","wrong":"","symbol":"Difficulty","correct":"import { Difficulty } from 'bsmap'"}],"quickstart":{"code":"import * as bsmap from 'bsmap';\nimport { readFileSync, writeFileSync } from 'fs';\n\n// Read a v4 difficulty file\nconst inputPath = './ExpertPlus.beatmap.dat';\nconst outputPath = './ExpertPlus_modified.beatmap.dat';\n\nconst rawData = readFileSync(inputPath, 'utf-8');\nconst data = bsmap.readDifficultyFileSync(rawData, 4);\n\n// Modify: add a note at beat 10, line 0, layer 1, color red\nconst note = new bsmap.V4Note({\n  beat: 10,\n  color: 0, // Red\n  line: 0,\n  layer: 1,\n  direction: 1, // Down\n  type: 0, // Note\n});\ndata.difficulty.colorNotes = data.difficulty.colorNotes || [];\ndata.difficulty.colorNotes.push(note);\n\n// Write back\nconst serialized = bsmap.writeDifficultyFileSync(data, 4);\nwriteFileSync(outputPath, serialized, 'utf-8');\nconsole.log('Done! Modified note added.');","lang":"typescript","description":"Reads a v4 difficulty file, adds a note at beat 10, and writes the modified beatmap back. Uses synchronous file I/O and the V4Note wrapper."},"warnings":[{"fix":"Replace new Beatmap(data) or Beatmap.create(data) with Beatmap.fromJSON(data).","message":"In v1.6.0, constructor and create() static method were removed. Use fromJSON() static method instead.","severity":"breaking","affected_versions":">=1.6.0"},{"fix":"Use import * as bsmap from 'bsmap' (ESM) or const bsmap = require('bsmap') (CJS).","message":"In v2.0.0, the main export changed from default to namespace. import * as bsmap from 'bsmap' is now required, import bsmap from 'bsmap' no longer works.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Import utility classes from their respective subpaths for tree-shaking and future compatibility.","message":"In v2.0.0, some utility classes (e.g., Beats) moved to subpath exports like 'bsmap/beats'. Direct import from main may be removed in future.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Update any v3 beatmap code to handle new FX event structures. Old v3 events still parse but may not serialize correctly.","message":"In v1.5.0, v3 beatmap schema updated to 3.3.0. Events collection classes changed; FX Event Box Group and FX Events Collection added.","severity":"breaking","affected_versions":">=1.5.0"},{"fix":"Use ESM (import * as bsmap from 'bsmap') in TypeScript or with ts-node. For plain JS, types are not needed.","message":"When using Node.js CJS with require('bsmap'), TypeScript types will not be available. You must use a separate type declaration or ESM.","severity":"gotcha","affected_versions":"*"},{"fix":"Always provide all required fields or use fromJSON() to fill defaults. Use the 'defaults' utility to apply schema defaults if needed.","message":"Partial creation of beatmap objects: absent fields default to undefined, not schema defaults. Missing required fields may cause validation errors on save.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-05-01T00:00:00.000Z","next_check":"2026-07-30T00:00:00.000Z","problems":[{"fix":"Use Beatmap.fromJSON(data) instead of new Beatmap(data).","cause":"Using static create() method which was removed in v1.6.0, or incorrectly calling constructor as a function.","error":"TypeError: Class constructor Beatmap cannot be invoked without 'new'"},{"fix":"Create script.js and add import * as bsmap from 'bsmap' (ESM) or use require('bsmap') (CJS).","cause":"Running ESM without 'type':'module' in package.json, or using wrong import style (default import instead of namespace).","error":"ERR_MODULE_NOT_FOUND: Cannot find module 'bsmap'"},{"fix":"Import Beats from only one source, preferably 'bsmap/beats'.","cause":"Importing Beats from both main and subpath 'bsmap/beats'.","error":"Duplicate identifier 'Beats'"},{"fix":"Update to bsmap >=1.5.0 and use the correct schema property names (e.g., colorNotes instead of notes).","cause":"Using an older version of bsmap (<1.5.0) that uses different property names for v4.","error":"Property 'colorNotes' does not exist on type 'V4Difficulty'"}],"ecosystem":"npm","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null}