feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
/**
|
|
|
|
|
* proBoardRegistry — runtime registration seam for boards a private overlay
|
|
|
|
|
* (velxio.com) ships outside the OSS tree.
|
|
|
|
|
*
|
|
|
|
|
* The OSS BoardKind union and its compiler-enforced Record maps stay exactly
|
|
|
|
|
* as they are for the open boards. An overlay calls registerProBoards() at
|
|
|
|
|
* mount with data-only definitions; registration patches the exported maps in
|
|
|
|
|
* types/board.ts (labels / FQBN / MicroPython set) so every existing read site
|
|
|
|
|
* keeps working untouched, and the handful of sites a map can't cover (canvas
|
|
|
|
|
* render, pin-name mapping, simulator construction, firmware load) consult
|
|
|
|
|
* getProBoard() as a fallback.
|
|
|
|
|
*
|
|
|
|
|
* The OSS build never registers anything here — like the proRoutes /
|
|
|
|
|
* __velxio_pro_gate__ / registerComponentDoc seams, this module is dead code
|
|
|
|
|
* until an overlay imports it. Board ad cards (ONLINE_ONLY_BOARD_ADS) hide
|
|
|
|
|
* automatically for registered kinds: the picker filter checks
|
|
|
|
|
* `ad.id in BOARD_KIND_LABELS`, and registration inserts the label.
|
|
|
|
|
*/
|
|
|
|
|
import type React from 'react';
|
|
|
|
|
import {
|
|
|
|
|
BOARD_KIND_LABELS,
|
|
|
|
|
BOARD_KIND_FQBN,
|
|
|
|
|
BOARD_SUPPORTS_MICROPYTHON,
|
2026-07-28 13:45:56 +07:00
|
|
|
registerPiFamilyKind,
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
type BoardKind,
|
|
|
|
|
} from '../types/board';
|
|
|
|
|
|
|
|
|
|
/** Structural contract for an overlay-provided in-browser board simulator.
|
|
|
|
|
* Mirrors the surface the store already uses on RP2040Simulator — the store
|
|
|
|
|
* only ever duck-types these members for pro simulators. */
|
|
|
|
|
export interface ProBoardSimulator {
|
|
|
|
|
/** Brand flag so the store can recognize overlay simulators without a class. */
|
|
|
|
|
readonly isProBoardSimulator: true;
|
|
|
|
|
onSerialData: ((ch: string) => void) | null;
|
|
|
|
|
onPinChangeWithTime: ((pin: number, state: boolean, time: number) => void) | null;
|
|
|
|
|
stop(): void;
|
|
|
|
|
detachPioPeripheral?(): void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProBoardDef {
|
|
|
|
|
/** The board id — behaves like a BoardKind everywhere at runtime. */
|
|
|
|
|
kind: string;
|
|
|
|
|
label: string;
|
|
|
|
|
/** arduino-cli FQBN, or null when the board has no backend compile. */
|
|
|
|
|
fqbn: string | null;
|
|
|
|
|
/** One-line picker description. */
|
|
|
|
|
description: string;
|
|
|
|
|
/** The board's custom-element tag. The overlay's import must have run
|
|
|
|
|
* customElements.define for it before the board is placed. */
|
|
|
|
|
tag: string;
|
|
|
|
|
/** True pixel size of the element (selection ring + pin overlays). */
|
|
|
|
|
size: { w: number; h: number };
|
|
|
|
|
supportsMicroPython?: boolean;
|
|
|
|
|
/** ESP32 run-path routing: the base chip the board carries. Routes the run
|
|
|
|
|
* through the ESP32 bridge path and picks the machine/engine type. Omit for
|
|
|
|
|
* boards that provide createSimulator (RP2350 class) or AVR/RP2040. */
|
|
|
|
|
esp32Family?: 'esp32' | 'esp32-s3' | 'esp32-c3' | 'esp32-c6';
|
2026-07-28 13:45:56 +07:00
|
|
|
/** QEMU-Linux run-path routing: route this kind through the Raspberry Pi
|
|
|
|
|
* bridge (backend qemu WebSocket, VFS panel, boot terminal). The overlay
|
|
|
|
|
* must also register a matching backend profile for the kind. */
|
|
|
|
|
piFamily?: boolean;
|
2026-07-28 19:36:13 +07:00
|
|
|
/** One shell line sent to the guest right after it reaches the boot
|
|
|
|
|
* prompt (piFamily boards only). Lets a board de-brand the generic
|
|
|
|
|
* image, e.g. set its own hostname/PS1 and clear the stock motd. */
|
|
|
|
|
guestSetup?: string;
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
/** Canvas renderer. Receives the placed board's props; return a React node.
|
|
|
|
|
* When omitted, the canvas renders `<tag id=... style=absolute@x,y>`. */
|
|
|
|
|
render?: (props: { id: string; x: number; y: number; running: boolean }) => React.ReactNode;
|
|
|
|
|
/** pinInfo name -> GPIO number (power/ground pins -> -1). Falls back to the
|
|
|
|
|
* generic numeric parse when omitted. Return null for "not mine". */
|
|
|
|
|
pinToNumber?: (pinName: string) => number | null;
|
|
|
|
|
/** In-browser simulator factory (e.g. the RP2350/Hazard3 emulator). The pm
|
|
|
|
|
* argument is the store's PinManager instance. */
|
|
|
|
|
createSimulator?: (pm: unknown) => ProBoardSimulator;
|
|
|
|
|
/** Load compiled firmware into a createSimulator() instance at run time —
|
|
|
|
|
* the overlay owns the whole sequence (PIO attach, binary load, demo I2C
|
2026-07-23 02:22:40 +07:00
|
|
|
* devices, ...). `program` is the compiled artifact exactly as the store
|
|
|
|
|
* holds it (base64/hex string, same value RP2040Simulator.loadBinary gets). */
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
loadFirmware?: (
|
|
|
|
|
sim: ProBoardSimulator,
|
2026-07-23 02:22:40 +07:00
|
|
|
program: string,
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
ctx: { boardKind: string; boardId: string },
|
|
|
|
|
) => void;
|
|
|
|
|
/** Built-in bridge sensors registered without wiring (e.g. an on-board I2C
|
|
|
|
|
* keyboard): pushed into the ESP32 bridge's sensor config on every run. */
|
|
|
|
|
builtInSensors?: Array<{ sensor_type: string; pin: number; addr?: number }>;
|
|
|
|
|
/** Built-in microSD on a shared SPI bus: the CS pin the bridge must gate.
|
|
|
|
|
* (A standalone SD card component still overrides this to un-gated.) */
|
|
|
|
|
builtInSdCsPin?: number;
|
2026-07-23 03:33:46 +07:00
|
|
|
/** Built-in peripheral attachment for a RUNNING board (LCD decoder onto the
|
|
|
|
|
* element's own canvas, speaker, on-board button/keyboard event forwarding).
|
|
|
|
|
* Called shortly after run start with the board's DOM element plus its
|
|
|
|
|
* simulator shim and ESP32 bridge (either may be null depending on the run
|
|
|
|
|
* path); must return a cleanup that detaches everything. */
|
|
|
|
|
attachBuiltins?: (ctx: {
|
|
|
|
|
el: HTMLElement;
|
|
|
|
|
sim: unknown;
|
|
|
|
|
bridge: unknown;
|
|
|
|
|
}) => () => void;
|
|
|
|
|
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
/** Sidebar / toolbar accents (fall back to a neutral chip icon). */
|
|
|
|
|
icon?: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const registry = new Map<string, ProBoardDef>();
|
|
|
|
|
|
2026-07-23 11:59:46 +07:00
|
|
|
// Registration happens when the overlay's dynamic import lands - potentially
|
|
|
|
|
// AFTER a consumer rendered and memoized its board list. Subscribers re-render
|
|
|
|
|
// on every registration (same contract as proRoutes / registerProExamples).
|
|
|
|
|
let version = 0;
|
|
|
|
|
const listeners = new Set<() => void>();
|
|
|
|
|
|
|
|
|
|
export function subscribeProBoards(cb: () => void): () => void {
|
|
|
|
|
listeners.add(cb);
|
|
|
|
|
return () => listeners.delete(cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getProBoardsVersion(): number {
|
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
export function registerProBoards(defs: ProBoardDef[]): void {
|
|
|
|
|
for (const def of defs) {
|
|
|
|
|
registry.set(def.kind, def);
|
|
|
|
|
const kind = def.kind as BoardKind;
|
|
|
|
|
// Patch the exported maps so every existing read site sees the board —
|
|
|
|
|
// labels also make the picker's ONLINE ad for this kind disappear.
|
|
|
|
|
(BOARD_KIND_LABELS as Record<string, string>)[kind] = def.label;
|
|
|
|
|
(BOARD_KIND_FQBN as Record<string, string | null>)[kind] = def.fqbn;
|
|
|
|
|
if (def.supportsMicroPython) BOARD_SUPPORTS_MICROPYTHON.add(kind);
|
2026-07-28 13:45:56 +07:00
|
|
|
if (def.piFamily) registerPiFamilyKind(def.kind);
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
}
|
2026-07-23 11:59:46 +07:00
|
|
|
version++;
|
|
|
|
|
for (const l of listeners) l();
|
feat(boards): runtime board-registration seam for private overlays
registerProBoards() lets a hosted overlay ship boards outside the OSS tree as
data-only definitions: registration patches the exported BoardKind maps
(labels / FQBN / MicroPython) so every existing read site keeps working, and
the sites a map can't cover consult the registry — canvas render (custom
element or overlay render fn), BOARD_SIZE, pin-name mapping, picker list +
descriptions + tag, ESP32 family routing, in-browser simulator construction
and firmware load (structural ProBoardSimulator contract, duck-typed PIO
attach/detach), built-in bridge sensors, and a CS-gated built-in microSD
(sdCsPin -> sd_card.cs_pin worker config). Esp32Bridge additionally gains the
esp32-c6 machine type + TX pin (public chip knowledge — the C6 compile path
already ships) and a generic sendKey() for built-in matrix keyboards.
registerProExamples() appends gallery examples at runtime; the board ONLINE
ads recompute at render so registration hides them. OSS behavior without an
overlay is unchanged — the registry is dead code, same as the other seams.
2026-07-23 02:21:21 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getProBoard(kind: string): ProBoardDef | undefined {
|
|
|
|
|
return registry.get(kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function listProBoards(): ProBoardDef[] {
|
|
|
|
|
return Array.from(registry.values());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function isProBoardSimulator(sim: unknown): sim is ProBoardSimulator {
|
|
|
|
|
return !!sim && (sim as { isProBoardSimulator?: boolean }).isProBoardSimulator === true;
|
|
|
|
|
}
|