ScoreScript Language wiki

Install and use in other tools

SetupInterfaceWhat it provides
Terminal or build pipelineNative scorescript CLICheck, format, import, and export files
Personal websiteSVG/PDF, or browser WASMStatic notation, or local interactive rendering
Node or ElectronGenerated Node WASM packageA reusable compiled document
Code editorscorescript lspLanguage-server integration
Agent clientscorescript-mcpNative tools and reference resources

The source-build instructions below require authorized access to the ScoreScript repository. They do not require a public npm or crates.io package. This documentation does not provide a verified public package-install route; do not assume an identically named registry package is this engine.

Install the command-line tool

Prerequisites: an authorized checkout, Rust/Cargo compatible with that checkout, and the platform's Rust build tools. If you keep several checkouts, give each its own CARGO_TARGET_DIR. From the repository root:

cargo install --locked --path crates/scorescript_cli --no-default-features
scorescript --help
scorescript docs --list

Cargo installs the binary into its configured bin directory; that directory must be on PATH. Omit --no-default-features if the terminal-score picture feature is wanted. The smaller build still checks, formats, renders SVG, and exports PDF and MIDI. Installing the CLI does not install the ScoreScript desktop app.

scorescript check piece.scorescript
scorescript render piece.scorescript -o piece.svg
scorescript pdf piece.scorescript -o piece.pdf
scorescript midi piece.scorescript -o piece.mid

For an automated build, stop when check exits nonzero. Preserve diagnostics; a renderer can draw partial output even when source has errors. Pin the engine revision used by a build so upgrading it is a deliberate change.

Node and Electron

Prerequisites: the checkout, Rust/Cargo, wasm-pack, and Node. From the repository root, build the Node-target package:

bash crates/scorescript_wasm/build.sh node

This creates crates/scorescript_wasm/pkg-node/ and runs its packaged-runtime smoke check. Copy the whole generated package into your application's vendor/scorescript/ directory. Keep its JavaScript and WASM from the same build. Save this example as render.cjs in your application root:

const { readFileSync, writeFileSync } = require("node:fs");
const { CompiledDocument } = require("./vendor/scorescript/scorescript.js");

const score = new CompiledDocument(readFileSync("piece.scorescript", "utf8"));
try {
  const diagnostics = JSON.parse(score.diagnostics_json());
  if (diagnostics.length) console.error(diagnostics);
  if (diagnostics.some(d => d.severity === "error")) {
    throw new Error("ScoreScript source contains errors");
  }
  writeFileSync("piece.svg", score.render_svg(JSON.stringify({ width_px: 800 })));
} finally {
  score.free();
}

Run node render.cjs. The Node build uses CommonJS and needs no asynchronous initialization. The browser build uses ES modules and does require initialization; the two generated packages are not interchangeable.

For an editor, retain one CompiledDocument per open file and call update(source) when its text changes. Then read diagnostics, notation, and performance from that same document. Call free() when closing it. In Electron, keep filesystem access behind the application's existing trusted host boundary; do not enable Node access in an untrusted page to run this example.

Document API

The generated type declarations (scorescript.d.ts) describe the exact API of your build. JSON-returning methods return strings; decode them with JSON.parse. Option arguments are JSON strings, not JavaScript objects.

MethodResult
update(source)Compile changed text; unchanged text keeps the same revision
revision()Current revision as a decimal string
diagnostics_json()Codes, severity, messages, and source ranges
render_svg(optionsJson)Flowing SVG; options include width_px and foreground
render_pages_json(optionsJson)Paginated SVG sheets and a layout report; every sheet carries its number and a digest of its own bytes, and {"since": "<revision>"} answers only the sheets that changed since that revision
event_geometry_json(optionsJson)Event boxes and system positions for hit testing
performance_json()Notes and timing data, not audio output
performance_json_for(movement)Performance for an authored movement ID
performance_json_with_options(movement, playOptional)The same movement with optional alternatives included when true; default playback omits them
position_clock_open_json(requestJson)Retain one performance with exact timing and optional practice tempo/pulse settings
position_clock_query_json(requestJson)Exact arrival/release times at written positions in that reading, including rests and ties
position_clock_release_json(requestJson)Release that reading's handle
format()Canonical source text; it does not save the file
free()Release the document when it is no longer used

Use the option shape belonging to the output method; flowing and paginated layout options are not interchangeable. parse_json() exposes the parsed structure, not a substitute for checking semantic diagnostics.

Practice playback and source edits

Open a position-clock reading with traversal: "straight-through". Use its returned performance and occurrence table together; do not interpolate silent beats from nearby notes. Handles stay bound to their source revision and must be released when no longer used. Optional tempo scaling, beat-head emphasis and subdivision strikes change that reading, not the saved score. Derived strikes are separate from authored notes. The position-clock methods are available in the lean WASM build too.

Authored pan -100 through pan 100 stays in the part's source. Performance parts include its native projections; tempo rows include the written range's upper endpoint (or null) and the effective quarter_bpm. The first number of a range is the initial playback rate.

Native application bridges can use scorescript_entry::step_grid, part_pan and bar_ops for revision-checked musical edits. These Rust APIs can set notes/rests, meter, tempo, bar structure and pickup length while preserving unselected music. They are not extra methods on the WASM document class; unsupported shapes refuse without changing the source. A host should show these refusals instead of repairing music with its own text substitutions.

Code editors and Markdown pipelines

Configure an editor's language-server client to launch scorescript lsp over stdio for .scorescript files. Syntax highlighting and preview UI are separate editor integrations; launching the server does not add those automatically.

A Markdown fence tagged scorescript is source text, not a universal embed standard. A Markdown site needs a build plugin or browser component that sends that fence to the native CLI or WASM engine. The simplest pipeline renders an SVG during the site build and replaces the fence with an image and source link. See website embedding for both approaches.

Agent clients

Build the native stdio server from the repository root:

cargo install --locked --path hosts/chatgpt-mcp

Set the client's MCP server command to the installed scorescript-mcp binary, with no arguments, using that client's configuration format. Client setup and support for previews or attachments vary; a stdio process is not a public HTTP endpoint.

The server exposes compile_score, update_score, format_score, read_score, render_score, export_score_file, and import_musicxml. Read scorescript://docs/index first, then the specific chapter resource, such as scorescript://docs/structure. These are the same authored chapters available through scorescript docs and this website.

For an existing document, use update_score with an increasing revision. The server returns artifacts for the client to save; it does not accept an arbitrary path and write into the client's filesystem. Ordinary terminal file work can use the CLI directly without an MCP round trip.

Verifying from a terminal

An agent working on files rather than through the server writes, then checks, then proves, then looks:

scorescript check piece.scorescript      # does it compile, and what came out
scorescript proof piece.scorescript      # every engraved bar, note by note
scorescript png   piece.scorescript --all   # the printed sheets, as pictures

Everything is in this CLI; never script around it with Python or other tools. check ends with one understood line carrying the bar, note and syllable totals and source lines that produced no music, so a loss the diagnostics cannot see is still visible in one line. proof prints the engraved model itself, one line per bar per voice, with --format json for a machine reader — that is the door for verification that never opens a picture, and it costs about what a check costs. render_score and png are for a reader that wants to look at the page.