Skip to content

DSL Overview

The song generator

Every Nimbus program is a JavaScript generator function:

function* song(ctx) {
// ...
}

function* makes song a generator. The engine calls it once per cycle and collects everything you yield. ctx is the cycle context object.

ctx.cycle is the current cycle number, starting at 0.

Yield patterns

yield cast(...) sends one pattern to the engine for the current cycle. You can yield multiple times to play multiple parts simultaneously:

function* song(ctx) {
const key = scales(4, 'C4:major')
const synth = vasynth({ wave: 'sawtooth', gain: 0.5 })
const kk = kick({ freq: 58, gain: 0.7 })
yield cast(synth, key, seq(4, '0,2,4,~'), ctx)
yield cast(kk, 'drums', seq(4, 'x.x.'), ctx)
}

Branch with ctx.cycle

Use ctx.cycle to change phrases over time:

if (ctx.cycle % 4 === 0) {
yield cast(bells, key, seq(4, '(every4:0)'), ctx)
}

Cycle length

The beatsPerCycle control in the header sets how many beats each cycle contains. Options: 4 / 8 / 16. The engine uses this value for all timing calculations. ctx.beatsPerCycle exposes the current setting inside the generator.

Structuring longer pieces

Use arrange() instead of manual ctx.cycle branching to describe multi-section compositions:

yield* arrange(ctx, [
{ name: 'intro', cycles: 8, patterns: [cast(bass, key, bassSeq, ctx)] },
{ name: 'verse', cycles: 16, patterns: [cast(bass, key, bassSeq, ctx), cast(lead, key, leadSeq, ctx)] },
{ name: 'chorus', cycles: 8, patterns: [cast(bass, key, chorusSeq, ctx), cast(lead, key, leadSeq, ctx)], crossfade: 4 },
])

For self-evolving patterns, see Generative — markov() & lsys().