Channels

SBCanvas.channel(name) creates or joins a named pub/sub channel for widget-to-widget communication. Any widget can publish data, and any widget subscribed to that channel receives it.

Creating a Channel

const ch = SBCanvas.channel('score');
Channel names must be alphanumeric with underscores only (e.g. score, timer_state, combo).

Publishing

const ch = SBCanvas.channel('score');
ch.publish({ team: 'blue', points: 42 });

Subscribing

const ch = SBCanvas.channel('score');
ch.subscribe((data) => {
  document.getElementById('score').textContent = data.points;
});
Late subscribers receive the most recent published value immediately on subscribe.

Unsubscribing

function handler(data) { /* ... */ }
ch.subscribe(handler);
ch.unsubscribe(handler);

Last Value

Access the most recent published value without subscribing:
const ch = SBCanvas.channel('score');
console.log(ch.lastValue); // last published data, or null

Example: Timer + Alert Coordination

Timer widget publishes countdown state:
const ch = SBCanvas.channel('countdown');
let remaining = 60;

SBCanvas.setInterval(() => {
  remaining--;
  ch.publish({ remaining });

  if (remaining <= 0) {
    ch.publish({ remaining: 0, done: true });
  }
}, 1000);
Alert widget reacts when the countdown hits zero:
const ch = SBCanvas.channel('countdown');
ch.subscribe((data) => {
  if (data.done) {
    SBCanvas.confetti();
    SBCanvas.toast('Time is up!');
  }
});

Example: Shared Theme

Settings widget publishes theme changes:
const ch = SBCanvas.channel('theme');
ch.publish({ bg: '#1a1a2e', accent: '#8B5CF6', font: 'Inter' });
All other widgets subscribe and update their styles:
const ch = SBCanvas.channel('theme');
ch.subscribe((theme) => {
  document.body.style.backgroundColor = theme.bg;
  document.body.style.setProperty('--accent', theme.accent);
});

API Reference

MethodReturnsDescription
SBCanvas.channel(name)WidgetChannelCreate or join a named channel
ch.publish(data)voidSend data to all subscribers
ch.subscribe(fn)voidReceive publishes (+ lastValue on join)
ch.unsubscribe(fn)voidStop receiving
ch.lastValueanyMost recent published value