Writing a sketch

Reading the audio

window.sialk, the versioned surface your sketch is written against.

A documented, versioned global object that your sketch is written against. It carries the audio Sialk hears, the show's transport position, and the surface you are drawn on.

Current version: v1.0.0, published 29 August 2026, and frozen. Additions arrive as minor versions. A removal or a changed meaning would be a major version, served alongside v1 rather than replacing it, a sketch written today does not stop working because Sialk moved on.

The full specification is published separately.

Why it exists

Compositing a sketch does not make it audio-reactive. The audio has to reach the page, and the page has to know what it is receiving.

Everywhere else in this field, audio reaches a page only through an OSC or WebSocket bridge you wire up yourself, which means every sketch has its own private arrangement, and none of them travel.

The whole surface

window.sialk = {
  contractVersion: '1.0.0',
  host: { name: 'sialk' | 'shim', version: string },

  audio: {
    level:         number,        // 0..1  broadband loudness, smoothed
    bass:          number,        // 0..1  ~20-250 Hz
    mid:           number,        // 0..1  ~250-2000 Hz
    high:          number,        // 0..1  ~2000-16000 Hz
    spectrum:      Float32Array,  // 64 bins, log-spaced 20 Hz - 16 kHz
    levelTrail:    Float32Array,  // 128 frames of level, [0] is newest
    hits:          number,        // monotonic onset counter
    onBeat:        number,        // 1 on the beat, decaying before the next
    beatPhase:     number,        // 0..1 between beats; 0 when bpm is 0
    bpm:           number,        // 0 when unknown
    bpmConfidence: number,        // 0..1, 0 when unknown
    silent:        boolean,       // true after 1s with no signal
  },

  transport: {
    time:    number,   // seconds, show position - may be scrubbed or reset
    elapsed: number,   // seconds since this sketch loaded, monotonic
    delta:   number,   // seconds since the previous frame
    frame:   number,   // frames since load
    running: boolean,
  },

  output: { width: number, height: number, fps: number },

  parameters: { /* see Declaring parameters */ },
};

Anything not listed is not guaranteed to exist. That is what makes the version meaningful.

Using it safely

The values are mutated in place, once per frame. Read them in your draw loop; do not cache them.

const s = window.sialk;
if (s) {
  // react
}

Guarding like this lets the same file run in a plain browser, where window.sialk is simply absent.

Running outside Sialk

@sialk/shim puts the same object on window.sialk in an ordinary browser tab, fed from the microphone. host.name tells you which one you are in - 'sialk' or 'shim'.

That is how you develop: browser tab, refresh, iterate. Then drag the folder onto Sialk and it behaves the same, because it is the same contract.

Microphone access needs localhost or HTTPS, a local static server qualifies, file:// does not.

transport.time and transport.elapsed

Not the same thing, and the difference matters.

  • elapsed is monotonic seconds since your sketch loaded. Use it for anything that should simply keep going.
  • time is the show's transport position. It may be scrubbed or reset. Use it for anything that should follow the show.

An animation driven by time that assumes it only ever increases will jump. That is not a bug in the contract; it is the transport doing its job.

In GLSL

The same values arrive as uniforms rather than as an object, see writing a GLSL sketch.