Tzopilotl — Getting Started
Installing the distribution, setting up your environment, and configuring projects.
1. Installing
Tzopilotl ships as a disk image, Tzopilotl-<version>.dmg. Open it and drag the Tzopilotl folder anywhere you like — /Applications, your home directory, a projects drive. There is no installer and nothing is written outside the folder.
The folder is self-contained and relocatable: the app and the command-line tool find the standard library and examples relative to their own location. The one rule is to keep the folder together — don't move Tzopilotl.app out on its own, or it will no longer find its sibling modules/ directory.
1.1 What's in the folder
Tzopilotl/ Tzopilotl.app the app: editor, notebooks, REPL, audio engine bin/tzpl command-line interpreter and REPL (language only) modules/ the standard library (std.*, music.*, ugens, ...) examples/ runnable demos -- open one in the app docs/ this guide and the reference documentation editors/ syntax packages for VS Code, TextMate, tree-sitter README.txt
Your own work never lives inside this folder (see §5); files opened from examples/ open as unsaved copies, so the originals stay pristine.
1.2 First launch & Gatekeeper
Official releases are signed and notarized, so macOS opens them without complaint. If you are running a build that isn't (for example one you built from source without a signing identity), macOS will refuse the first double-click: right-click Tzopilotl.app and choose Open once, and it runs normally from then on.
1.3 Requirements
- macOS. The app uses CoreAudio; no other audio drivers are needed. (TZPL also builds and runs on Linux, but there is no packaged Linux release yet — build it from source; see
docs/LINUX.mdin the repository.) - Xcode Command Line Tools. Compiling synth definitions uses the system C++ compiler. If synthdef compilation fails with a missing-compiler error, install the tools with:
xcode-select --install
1.4 Updating
Replace the whole Tzopilotl/ folder with the new version. Nothing of yours is stored inside it, so this is always safe. Never update pieces of it individually — the app, bin/tzpl, and modules/ are matched to each other.
modules/ is lost on the next update. To customize a standard module, copy it into your project's modules/ (or a $TZPL_PATH directory) — those are searched first and shadow the stdlib version (§4.1).2. First Sounds
Launch Tzopilotl.app and pick File > Open Example…. A good first stop is example_synthdefs.x (a corpus of synths with a playExamples() tour) or ui_synth_controls.x (a synth whose control surface materializes as live widgets).
Evaluation is cursor-driven, like other live-coding environments:
| Shortcut | Action |
|---|---|
| Cmd+Enter | evaluate the selection, or the block under the cursor |
| Shift+Enter | evaluate the current line |
| Cmd+Shift+Enter | evaluate the whole file (in a notebook: run all cells) |
| Cmd+K | clear the console |
Results and prints land in the console pane. For the notebook document format, widgets, and the full shortcut table, see Live Controls & Notebooks in this docs folder.
3. The Command Line
3.1 bin/tzpl
bin/tzpl is the Tzopilotl interpreter on its own: run it with no arguments for a REPL, or pass a .x file to execute it. Arguments after the filename are passed to the script (readable via the programArgs() builtin).
$ tzpl # interactive REPL
$ tzpl script.x # run a script
$ tzpl -I ~/mylibs script.x # add module search paths
Useful flags: -I <path> adds module search paths (colon-separated), --rt enables real-time-safety enforcement, and -h lists the rest.
bin/tzpl has no audio engine: it is for scripts, libraries, and learning the language. Modules that talk to the engine (audioEngine, synthdef compilation to a running graph, music.play, the ui widgets) only work inside the app.To call tzpl from anywhere, add the distribution's bin to your PATH in ~/.zshrc (adjust the path to wherever you put the folder):
export PATH="/Applications/Tzopilotl/bin:$PATH"
Symlinking bin/tzpl into a directory already on your PATH also works — the symlink is resolved before the interpreter looks for its standard library, so it still finds the distribution.
3.2 The app, headless
The app binary itself is scriptable. Launching it from a terminal on a file both opens that file and applies its project's configuration (§5.3):
$ /Applications/Tzopilotl/Tzopilotl.app/Contents/MacOS/Tzopilotl ~/music/mypiece/main.x
With --nogui it runs the same engine without a window, and with --nrt <out.wav> it renders a script offline to a WAV file instead of opening an audio device:
$ .../MacOS/Tzopilotl --nrt out.wav --duration 30 piece.x
All engine settings (§5.2) have matching command-line flags (--sample-rate, --device, --silos, …) that override the project config; run with --help for the full list.
4. Environment Variables
No environment variables are required. The distribution is self-locating; the two below exist for customizing where modules come from. Set them in ~/.zshrc for terminal use. (The Finder-launched app does not read your shell profile, but it doesn't need to — it finds everything relative to itself.)
| Variable | Meaning |
|---|---|
TZPL_PATH | Colon-separated list of extra module directories, searched before the standard library. Use it for personal libraries you want available in every script: export TZPL_PATH="$HOME/tzpl-libs" |
TZPL_HOME | Explicit path to a distribution root (a folder containing modules/). Overrides the executable-relative discovery. Rarely needed — only when you want a binary to use a stdlib other than the one it shipped with, e.g. pointing a dev build at an installed distribution or vice versa. |
4.1 Import search order
Each import is resolved by searching, in order:
- the directory of the importing file
-Ipaths from the command line- the project's
modules/directory (§5.4) $TZPL_PATHdirectories- the standard library:
$TZPL_HOME/modulesif set, otherwise the distribution'smodules/found relative to the executable - the distribution's
examples/(so examples can import each other, and your scripts canimport instrument_synthdefs.*)
Earlier entries win, so a file with the same module name in your project shadows the stdlib version. This is the supported way to customize standard modules — copy, then edit the copy.
5. Projects & Configuration
A project is any folder containing a file named tzpl-config. That file is the marker and the engine configuration; the folder may also contain a modules/ directory for project-local modules, plus your .x sources and .tzd notebooks laid out however you like.
File > New Project… creates one for you: a folder with a commented-out tzpl-config template, an empty modules/ directory, and a starter main.tzd notebook. File > Open Recent Project reopens a project at its last document.
When you open any file inside a project (the app walks up from the file to the nearest ancestor folder with a tzpl-config), the project is recognized: its modules/ joins the import path and its engine settings are applied at launch.
5.1 The tzpl-config file
Plain text, one key = value per line; -- starts a comment; string values may be quoted. Unknown keys are reported, not fatal. Every key is optional — an empty file is a valid project marker that changes no settings.
-- Tzopilotl project config
sampleRate = 44100
bufferFrames = 256
device = "MacBook Pro Speakers"
inputChannels = 2
5.2 Configuration keys
| Key | Default | Meaning |
|---|---|---|
device | "default" | Audio output device, by name (as shown in Audio MIDI Setup). "default" follows the system output. |
inputDevice | same as output | Audio input device, by name. |
sampleRate | 48000 | Sample rate in Hz. |
bufferFrames | 512 | Audio buffer size in frames. Lower is less latency, higher is more headroom. |
channels | 2 | Number of output channels. |
firstChannel | 0 | First output channel on the device (for multichannel interfaces). |
inputChannels | 0 | Number of input channels. 0 disables audio input. |
firstInputChannel | 0 | First input channel on the device. |
silos | 4 | Number of parallel audio processing units (silos). Each runs its own graph and scheduler. |
tempoClocks | 1 | Number of tempo-clock slots per silo. |
oscPort | 0 (off) | UDP port for the OSC server, in builds with OSC support. |
natsUrl | off | NATS server URL (e.g. "nats://127.0.0.1:4222"), in builds with NATS support. |
engineName | none | Engine name for namespaced NATS subjects when several engines share a server. |
5.3 When settings apply
Engine settings are read once, at app startup, from the project of the file the app is launched on. They cannot change while the engine is running, so:
- Opening a project file mid-session (File > Open, drag-and-drop, Finder) adds the project's
modules/to the import path immediately, but its engine settings wait until the next launch on that project. - After editing
tzpl-config, relaunch the app on the project to pick up the changes.
5.4 Project modules
Any .x file in the project's modules/ directory is importable by name from anywhere in the project. Because project modules are searched before the standard library, this is also where a copied-and-customized stdlib module goes. File > Reveal Modules Folder shows the distribution's own modules/ when you want to read (or copy) the originals.
6. Editor Support
The editors/ folder ships syntax highlighting for external editors:
editors/vscode— a VS Code extension (highlighting for.xfiles); see its README for installation.editors/Tzopilotl.tmbundle— a TextMate bundle, also usable by Sublime Text.editors/tree-sitter-tzpl— a tree-sitter grammar for editors that consume one (Neovim, Helix, Zed).
7. Where to Go Next
| Document | What it covers |
|---|---|
| Tzopilotl by Example | The language, syntax-first: types, functions, auto-mapping, pattern matching, modules. |
| Tzopilotl Music Cookbook | Task-oriented recipes for making sound and music — the best second stop after this guide. |
| Live Controls & Notebooks | The ui widget module and notebook documents in the app. |
| Builtin Functions | Reference for every built-in function. |
| Coroutines | Coroutines, scheduling, and time. |
| FFI Guide | The foreign-function interface, including the audio engine FFI. |
8. Troubleshooting
“Tzopilotl.app can't be opened” / “unverified developer”
An unsigned (source-built) copy: right-click the app and choose Open once. See §1.2.
Synthdef compilation fails with a compiler error
Install the Xcode Command Line Tools: xcode-select --install. Synth definitions are compiled to native code with the system C++ compiler.
An import isn't found, or the wrong version loads
Walk the search order in §4.1 — the first match wins. Check for a same-named file earlier in the chain (project modules/, a $TZPL_PATH directory) shadowing the one you expect, and check echo $TZPL_PATH for stale entries.
Audio imports fail in bin/tzpl
Expected: the command-line interpreter has no audio engine (§3.1). Use the app, or its headless mode (§3.2).
No sound
Check that the device in your project's tzpl-config names an existing output (or leave it at "default"), and remember engine settings apply at launch (§5.3). The console reports the device and sample rate the engine actually opened.
The app can't find the standard library
Tzopilotl.app or bin/tzpl was separated from the distribution folder. Put it back next to modules/, or set TZPL_HOME to a distribution root (§4).