A deterministic, sandbox-safe music runtime for documents.
Tartlet plays compositions written in the Strudel language family: mini-notation strings such as
"bd*2 [~ bd] sd ~" plus a chain of methods such as .gain(.8).room(.3). It never evaluates
the source as JavaScript. Text is parsed into a closed expression language, lowered to a typed
Music IR and compiled into pure pattern queries over exact rational time.
It was built so that compositions written by language models can live safely inside documents. The first host is the Markdown2 renderer. Tartlet does not depend on it.
setcpm(92 / 4);
$: s('bd*2 [~ bd] sd ~, hh*8').gain(0.8);
$: note('<d2 d2 f2 c2>').s('sawtooth').lpf(600).release(0.2);
$: n('<0 2 4 6>').scale('D:minor').s('triangle').room(0.4).slow(2);- Nothing is executed. No
eval,new Functionor string timers anywhere. Lint enforces this, and so does the playground's CSP, which has nounsafe-eval. - Deterministic. The same document, blob and seed always produce the same events. Random
choices come from explicit seed paths, never from
Math.random. - Exact time. Musical time is rational. It becomes floating-point seconds only at the scheduler.
- Graceful degradation. A broken track is muted. The other tracks keep playing. Diagnostics carry precise ranges, a muting effect, optional safe fixes and a compact repair payload for models.
- Embeddable. The core path (
time → mini → syntax → check → core) has no DOM or Web Audio dependency. It runs in Node, Deno, workers and browsers. - Safe audio. A master-bus limiter and a NaN/Infinity guard sit beneath every composition. Documents cannot bypass them.
- Apache-2.0, clean-room. See
CLEAN_ROOM.md.
Pre-release. The phases are defined in plan.md.
-
T0 (vertical spike): complete. The playground plays the
idea.md§13.1 example. -
T1 (real front end): implemented. This includes the full expression parser, the checker, the IR codec and validation, seeds, limits, the worker host and the CLI with its corpus harness. The cross-model regeneration check for
miniis pending. -
T2 (coverage drive): mostly implemented. This includes the T2 transforms, polymeter, random choice, signals,
.seed(),.label(), the resource catalog and the synthesized general kit. Still pending: oracle specifications,@tartlet/embed, the repair benchmark and growing the kit. -
T3 (projections and sound): in progress. Implemented: the audio quality pass (ADSR, filters, per-orbit reverb and delay, sample playback) and these Tartlet extensions:
- user-defined functions and a standard library of transforms;
- synthesis controls, voices and choirs that sing syllables;
- headphone and binaural controls, space presets and procedural textures;
- frequency-domain, impulse-response and response-curve DSP;
- host-supplied WAV samples and banks, with a CLI importer.
Not yet: the piano roll, Web MIDI, offline-render tests and the mixer UI.
Open interpretation questions are tracked in spec-issues.md (TS-1 to
TS-94 so far).
Requirements: Node ≥ 22 and pnpm 9 (corepack enable).
pnpm install
pnpm test # unit, conformance and property tests
pnpm --filter playground dev # open the playground
pnpm check # full quality gate: format, lint, typecheck, test, buildimport { check, locator } from '@tartlet/check';
import { compile } from '@tartlet/core';
import { rat } from '@tartlet/time';
const source = '$: s("bd*4")\n$: note("<c3 e3>").s("triangle")';
const result = check(source, { documentId: 'doc-1', blobIndex: '0' });
const program = compile(result.program, { locate: locator(source), documentId: 'doc-1', blobIndex: '0' });
const { events } = program.query({ begin: rat(0), end: rat(1) }, { provenance: true });To use it in a page:
<tartlet-player document-id="doc-1" blob-index="0">$: s("bd*4, hh*8")</tartlet-player>
<script type="module">
import { defineTartletPlayer } from '@tartlet/element';
defineTartletPlayer();
</script>- Getting started: setup, scripts, the CLI, Deno and deployment
- Architecture: pipeline, layer contracts, time, seeds and the dependency graph
- Package reference: what each
@tartlet/*package exports - Language reference: mini-notation and every supported function and control
- Diagnostics: every diagnostic id and the recovery policy
- Testing: test kinds, fixtures, property tests and the corpus harness
- Embedding:
<tartlet-player>, samples, evaluators, theming and CSP - Contributing: the clean-room rules, adding functions and DCO sign-off
- Instructions for AI agents: the rules and conventions in one checklist
- Extension design notes: instruments, vocals, binaural, DSP, noise, samples, language extensions, genetics and more ideas
- Design document and project plan
- ADRs and traceability
packages/: the runtime libraries, shipped as TypeScript source (exportspoints atsrc/index.ts)apps/playground/: the Vite demo app, deployed to S3 and CloudFront bydeploy.sh.albums/holds the bundled album catalogcollection/: the optional shared sample collection, served as/samples/next to the playground (see docs/samples.md)corpus/: prompt generation and model-output collection for coverage measurementoracle/: neutral behavioural specifications written by the oracle analyst (empty so far)clean-room-log/: one provenance entry per implementation sessione2e/: Playwright tests for the playgroundterraform/: hosting infrastructure for the playgrounddocs/: developer documentation, design notes and ADRs
Licensed under Apache-2.0. Every commit carries a DCO sign-off (git commit -s).
"Strudel" is named only to describe language compatibility. Tartlet is not affiliated with or endorsed by the Strudel project. Tartlet contains no Strudel, TidalCycles or SuperDirt code. Source and issues: https://github.com/SimiaCryptus/tartlet