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.
elapsedis monotonic seconds since your sketch loaded. Use it for anything that should simply keep going.timeis 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.