Package Management
A Resonon package is a directory — usually a git repository — that bundles reusable
code (a src/lib.non file) and/or sample kits (a kits/ directory). There’s no registry
and no publish step: packages live on GitHub and install with a gh:user/repo shorthand
that maps straight to a clone URL.
This guide covers scaffolding projects, the resonon.toml manifest, installing and
publishing packages, and the kit.toml sample-kit format. For the runtime CLI (running
files, the REPL, the server), see the CLI Reference.
Scaffolding a Project
Section titled “Scaffolding a Project”resonon init <name> scaffolds a project in the current directory; resonon new <name>
creates a new directory first. Both accept flags that choose the project type:
| Flag | Project type |
|---|---|
| (none) | Plain project with src/main.non. |
--lib | Library with src/lib.non (importable code). |
--kit | Sample-kit project with a kits/ directory. |
--native | Native Rust extension (implies --lib). |
Flags combine:
resonon new my-pkg --lib --kit # library plus sample kitsresonon new my-ext --lib --native # library backed by a native extensionEvery scaffold writes a resonon.toml manifest, a README.md, an MIT LICENSE, a
.gitignore, and initializes a git repository (unless you’re already inside one). A plain
project looks like this:
my-project/ resonon.toml src/ main.non # entry point — run with `resonon run` README.md LICENSE .gitignoreresonon run executes src/main.non from the project root. The generated .gitignore
excludes resonon.lock and dependencies/.
Project Setup
Section titled “Project Setup”The scaffolded src/main.non sets project metadata with builtins that double as your
project’s configuration:
project_title("My Project");project_artist("Your Name");project_bpm(120);| Builtin | Description |
|---|---|
project_title(string) | Set the project title. |
project_artist(string) | Set the artist name. |
project_bpm(bpm, beats_per_cycle?) | Set the project tempo in BPM. beats_per_cycle defaults to 4. |
project_bpm() establishes the tempo at startup. To change tempo live during a session,
use setbpm(bpm, beats_per_cycle?) instead — it takes effect immediately and is ignored
while Resonon is following an external MIDI clock. See Clock
Sync.
The Manifest (resonon.toml)
Section titled “The Manifest (resonon.toml)”resonon.toml declares package metadata and dependencies. It’s created automatically by
resonon init / resonon new:
[package]name = "my-project"version = "0.1.0"authors = ["Your Name <email>"]resonon = "0.8.0"
[dependencies]drums = { source = "gh:resonon/drum-kits", version = "v1.0" }synths = { source = "gh:user/synths" }[package]
Section titled “[package]”| Field | Required | Description |
|---|---|---|
name | Yes | Package name. |
version | No | Package version. |
authors | No | List of authors. |
resonon | No | Resonon version the project targets. |
[dependencies]
Section titled “[dependencies]”Each entry maps a package name to its source. The key is the local package name (the directory it installs into).
| Field | Required | Description |
|---|---|---|
source | Yes | Package source (gh:user/repo). |
version | No | Git tag to pin to (e.g. "v1.0"). |
[native]
Section titled “[native]”Present only for packages with a native Rust extension. See Native Extensions.
| Field | Required | Description |
|---|---|---|
crate | Yes | Path to the native Rust crate (relative to the project root). |
Installing Packages
Section titled “Installing Packages”The pkg subcommands have top-level aliases for the common cases:
| Full command | Alias |
|---|---|
resonon pkg install <source> | resonon install <source> |
resonon pkg update [name] | resonon update [name] |
| — | resonon install (no args — install all from resonon.toml) |
| — | resonon remove <name> |
Install from GitHub with the gh:user/repo shorthand, optionally pinning a tag with @:
resonon install gh:resonon/drum-kitsresonon install gh:resonon/drum-kits@v1.0Where packages install: inside a project (where resonon.toml exists) packages go to
dependencies/ relative to the project root and are recorded in resonon.toml and
resonon.lock. Outside a project they install to the global library path,
~/.resonon/lib/. Resonon searches both locations (and the current directory) when
resolving use imports and Sampler() paths.
After install, Resonon reports the package type and any kits:
Installed 'drum-kits' [kits] to ~/.resonon/lib/drum-kits Kits: 808 — Sampler(Kit("drum-kits/808")) vinyl — Sampler(Kit("drum-kits/vinyl"))Run resonon install with no arguments to install every dependency listed in
resonon.toml.
Listing & Inspecting
Section titled “Listing & Inspecting”resonon pkg list shows installed packages and their types:
Installed packages (dependencies/):
drum-kits [kits] kit: 808 — Sampler(Kit("drum-kits/808")) kit: vinyl — Sampler(Kit("drum-kits/vinyl")) my-lib [code] studio-tools [code+kits] kit: piano — Sampler(Kit("studio-tools/piano"))| Type | Meaning |
|---|---|
[code] | Has src/lib.non (importable code). |
[kits] | Has a kits/ directory. |
[code+kits] | Has both. |
resonon pkg inspect <name> prints a package’s documentation, code exports with
signatures, and kit details:
Package: my-lib [code+kits]
A collection of utility functions and drum kits.
Exports:
fn scaled(value, factor) let default_bpm = <number>
Kits:
lo-fi — oneshot mode, 12 samples Usage: Sampler(Kit("my-lib/lo-fi"))Updating & Removing
Section titled “Updating & Removing”resonon update [name] re-clones dependencies at their pinned tag (or the latest commit
when no version is set), rebuilds any native extensions, and regenerates resonon.lock:
resonon update # update all dependenciesresonon update drum-kits # update oneresonon remove <name> (project only) drops a dependency from resonon.toml and
resonon.lock and deletes its installed directory:
resonon remove drum-kitsCreating a Package
Section titled “Creating a Package”A package needs at least one of: a src/lib.non (code) or a kits/ directory (samples).
Both can coexist in one repository.
Code Packages
Section titled “Code Packages”Write src/lib.non with the functions and values you want to share. All top-level
fn, let, and class definitions are exported by default; mark items private to
keep them internal. /// doc comments appear in resonon pkg inspect, and the first
doc-comment block becomes the package description.
/// my-lib — utility helpers for generative rhythms./// The first doc-comment block becomes the package description.
private let lib_name = "my-lib";
/// Scale a value and round to the nearest integer.fn scaled(value, factor) { round(value * factor)}
/// Default tempo for performance templates.let default_bpm = 120;
/// Print a greeting. Internal — not exported.private fn greet() { PRINT f"Hello from {lib_name}!";}Kit Packages
Section titled “Kit Packages”Organize WAV files under kits/<kit-name>/. A kit is one subdirectory of kits/:
my-drums/ kits/ 808/ bd.wav sd.wav hh.wavIf you name files after GM drum abbreviations (bd, sd, hh, …),
Resonon auto-detects notes and you can skip kit.toml entirely. For explicit control, add
a kit.toml (see Kit Configuration).
Using Installed Packages
Section titled “Using Installed Packages”Import a package’s code with use "<name>" — the bare package name resolves to its
src/lib.non:
use "studio-tools";
let pattern = studio-tools.swing(42, 0.6);Load its kits with Sampler(Kit("<name>/<kit>")):
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("studio-tools/lo-fi")));drums << [bd sd bd sd];PLAY;See Modules for the full import system and Samplers for sampler details.
Kit Configuration (kit.toml)
Section titled “Kit Configuration (kit.toml)”A kit.toml controls how a kit’s samples are mapped and played. Every section is optional
— with no kit.toml, Resonon auto-detects WAV files in the directory.
[kit] — metadata
Section titled “[kit] — metadata”| Field | Type | Default | Description |
|---|---|---|---|
name | String | Directory name | Display name for the kit. |
author | String | — | Kit author. |
mode | String | "oneshot" | Playback mode: "oneshot" or "melodic". |
Oneshot plays each sample at a fixed pitch — standard for drums. Melodic repitches
samples relative to each sample’s root note — use it for tonal instruments.
[defaults] — bulk note mappings
Section titled “[defaults] — bulk note mappings”Map sample names to notes in one place instead of repeating note in every entry. Values
are note names ("C2", "F#3") or MIDI numbers (36, 42):
[defaults]bd = "C2"sd = "D2"hh = "F#2"[samples] — per-sample settings
Section titled “[samples] — per-sample settings”Each key defines a sample:
| Field | Type | Default | Description |
|---|---|---|---|
files | Array of strings | — | WAV paths relative to the kit directory. Multiple files enable round-robin. |
note | String or number | Auto-assigned | MIDI note that triggers this sample ("C2" or 36). |
root | String or number | — | Root pitch for melodic mode ("C4" or 60). |
choke_group | Number | — | Samples sharing a group cut each other off. |
velocity | Number | 1.0 | Default velocity (0.0–1.0). |
loop_start | Number | — | Loop start, normalized (0.0–1.0). |
loop_end | Number | — | Loop end, normalized (0.0–1.0). |
A drum kit with a choke group (the open and closed hats cut each other):
[kit]name = "Lo-Fi Drums"
[samples]bd = { files = ["kick.wav"] }sd = { files = ["snare.wav"], note = "D2" }hh = { files = ["hihat_closed.wav"], note = "F#2", choke_group = 1 }hh_open = { files = ["hihat_open.wav"], note = "A#2", choke_group = 1 }Multiple files per sample give automatic round-robin variation:
[samples]sd = { files = ["snare_1.wav", "snare_2.wav", "snare_3.wav"], note = "D2" }A melodic kit repitches relative to each root; use loop points for sustaining sounds:
[kit]name = "Tape Piano"mode = "melodic"
[samples]piano = { files = ["piano_c4.wav"], root = "C4" }pad = { files = ["pad_c3.wav"], root = "C3", loop_start = 0.1, loop_end = 0.95 }Note Resolution
Section titled “Note Resolution”When a sample has no explicit note, Resonon resolves it in order:
- Explicit
notein the[samples]entry. - A
[defaults]mapping. - The GM drum mapping below (by sample name).
- Sequential assignment from C2 (MIDI 36).
| Name | Aliases | Note |
|---|---|---|
bd | kick, bass | C2 (36) |
sd | snare | D2 (38) |
rs | rim, rimshot | C#2 (37) |
hh | hihat, hat, ch | F#2 (42) |
hh_open | hihat_open, oh | A#2 (46) |
cp | clap | D#2 (39) |
lt | tom, tom_low | A2 (45) |
mt | tom_mid | B2 (47) |
ht | tom_high, tom_hi | D3 (50) |
crash | cy | C#3 (49) |
ride | — | D#3 (51) |
cb | cowbell | G#3 (56) |
ma | maracas | A#4 (70) |
cl | clave | D#5 (75) |
lc | conga_low | E4 (64) |
mc | conga_mid | D#4 (63) |
hc | conga_high | D4 (62) |
With no kit.toml, each .wav becomes a sample named after its filename, notes come from
the table above (or sequentially from C2), and the mode defaults to oneshot — so a minimal
kit is just a folder of WAV files.
Native Extensions
Section titled “Native Extensions”A --native project adds a Rust crate under native/, a built-dylib directory lib/,
and a [native] section in resonon.toml. Build it with:
resonon build # build for the current platformresonon build --dist # platform-named output for binary distributionWriting native extensions — the resonon-ext crate, the #[ext_fn] macro, and calling
into Rust from .non — is covered in Going Native.
Publishing
Section titled “Publishing”Packages publish by pushing to GitHub — gh:user/repo maps directly to
https://github.com/user/repo.git. There’s no registry or publish command:
cd my-packagegit initgit add .git commit -m "Initial commit"gh repo create my-package --public --source=. --pushOthers then install it:
resonon install gh:yourname/my-packageVersioning. Tag releases with git tags. Consumers pin a tag in resonon.toml:
[dependencies]my-package = { source = "gh:yourname/my-package", version = "v1.0" }…or at install time with resonon install gh:yourname/my-package@v1.0. Without a pin,
install clones the latest commit on the default branch, and resonon.lock records the
exact commit so the install is reproducible.
Troubleshooting
Section titled “Troubleshooting”“Module not found” on use — Check the package is installed (resonon pkg list) and
that you’re using the repository name, not the [kit].name from kit.toml. The bare name
(use "drum-kits") resolves to the package’s src/lib.non.
“no lib.non or kits/ found” after install — The repository doesn’t follow the package
layout. Ensure code is at src/lib.non or kit WAVs are under kits/<kit-name>/.
Samples not loading — Confirm the kit directory holds .wav files (not .mp3/.flac)
and that the path has both parts: Sampler(Kit("package-name/kit-name")).
See Also
Section titled “See Also”- CLI Reference — the runtime CLI (
run, REPL, server). - Configuration —
config.tomland the~/.resononlayout. - Modules — the
useimport system. - Samplers — loading and playing sampler kits.
- Going Native — writing native Rust extensions.