Files
portal/web/js/api.js
Jimmy 5094c7bcee Add portal web simulator, SPI bridges, and Pico firmware updates.
Bring the five-panel hex portal online with a browser 3D/schematic preview, Pi SPI backends, and renamed multi-panel Pico UDP firmware.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 14:54:51 +12:00

57 lines
1.6 KiB
JavaScript

/** @typedef {{ index: number, width: number, height: number, position: string, label?: string }} PanelConfig */
/** @typedef {{ frame: number, animation: string, panels: Array<{ index: number, width: number, height: number, rgb: number[] }> }} FramePayload */
/** @typedef {{ panels: PanelConfig[], animations: string[], defaultFps: Record<string, number>, defaultBrightness: number }} PortalConfig */
/**
* @param {string} path
* @returns {Promise<PortalConfig>}
*/
export async function fetchConfig(path = "/api/config") {
const res = await fetch(path);
if (!res.ok) throw new Error(`config ${res.status}`);
return res.json();
}
export class FrameStream {
/** @param {() => void} onFrame */
constructor(onFrame) {
this._onFrame = onFrame;
this._source = null;
this._retry = null;
/** @type {(() => void) | null} */
this.onDisconnect = null;
}
/** @param {{ animation: string, brightness: number, fps: number }} opts */
start(opts) {
this.stop();
const params = new URLSearchParams({
animation: opts.animation,
brightness: String(opts.brightness),
fps: String(opts.fps),
});
this._source = new EventSource(`/api/stream?${params}`);
this._source.onmessage = (event) => {
this._onFrame(JSON.parse(event.data));
};
this._source.onerror = () => {
this.onDisconnect?.();
this.stop();
this._retry = setTimeout(() => this.start(opts), 1500);
};
}
stop() {
if (this._retry) {
clearTimeout(this._retry);
this._retry = null;
}
if (this._source) {
this._source.close();
this._source = null;
}
}
}