Skip to content

Architect — design a system

Build a broadcast system by drawing it. Drag components onto a canvas, wire their pins together, set their parameters, and apply — and what you drew becomes version-controlled configuration that the platform deploys and runs.

Architect — what you can place, and what happens to what you build WHAT YOU CAN PLACE — read from the registry, not maintained by hand containerregistryphrame/* images capabilitymanifest(OCI label) catalogvalidate ·group by type paletteinput · processoutput carries read offer WHAT YOU BUILD — a design, compiled into the schemas the services already read canvasplace · wiretyped pins inspectorschema-drivenparameters compilergraph → configsvdi://uuid GitLab commitphrame-config configure compile apply drag a component onto the canvas orchestration — placed onto a node, deployed, running live JPEG thumbnails + stats over MQTT (~1 Hz) come back to the canvas, so a design shows the running system


The configuration of a media system is a graph: sources feed processing, processing feeds outputs, and the interesting part is which thing is connected to which. Written down as JSON it is still a graph — just one whose edges are expressed as identifiers repeated in several files, where a mistake is a typo that validates cleanly and fails at run time.

Architect edits the graph as a graph.

  • The system is drawn, not transcribed. Placing and wiring components is the same act as authoring the configuration, so there is no step where intent gets translated into syntax by hand.
  • Only what actually exists can be placed. The palette is assembled by reading the container registry, so a component appears because an image was built that provides it — not because someone remembered to add it to a list.
  • You can see it working. Components show live preview thumbnails from the running system, roughly once a second, so the canvas shows what is happening rather than only what was intended.
  • Every change is a commit. Applying a design writes version-controlled configuration to GitLab. It is reviewable, attributable and revertible, and the deployment record and the deployment are the same object.

In one line: the system diagram is the configuration — so the picture on the wall and the thing that is running cannot disagree.


Place. An expandable palette down the left groups components into Input, Processing and Output. Drag one onto the canvas to instantiate it.

Configure. Each placed component has an inspector panel generated from that component’s own parameter definitions — text, numbers, booleans, selects — with validation and inline errors.

Wire. Components expose typed input and output pins. Dragging between them creates a connection, and the canvas refuses connections that are not valid — wrong direction, wrong type, or a pin that is already satisfied.

Some pins do not exist until the component is connected to its source. A demultiplexed sub-stream, or the flows carried by an attached MXL source, cannot be known in advance: they are properties of the thing that was plugged in. So the canvas is a dynamic surface, not a static form — a component can gain pins as you wire it up. This is the single most important thing to understand about using it, and it is the reason a plain configuration form could not do this job.

Watch. Where available, a component displays a live preview thumbnail sourced from the running system over MQTT at roughly 1 Hz, alongside its statistics.

Apply. Edits are local until applied. Applying commits the configuration to GitLab, and the deployment path described under Orchestration takes it from there — validated, distributed, placed onto a node, and started.

Some parameters can additionally be tuned live over MQTT, with the new value written back into the configuration. Live tuning therefore does not create an undocumented divergence between the running system and its record: the change persists as version-controlled state rather than as something only the desk remembers.


It deliberately reuses what the platform already has. Architect is not a parallel stack:

  • The canvas is React Flow (@xyflow/react) in a React + TypeScript + Vite frontend, using the existing Phrame component library and dark broadcast theme.
  • The GitLab gateway follows the phrame-config model — read and write through the GitLab API, with Redis-backed distributed locking, history and revert, and lock state broadcast over Socket.io so a second editor sees a file is held rather than discovering it at save time.
  • The configuration it produces is the existing schemas the services already consume — not an Architect-specific format. See What a design compiles to.
  • Previews and live control ride the same EMQX brokers and browser wss + JWT path as the other monitoring surfaces, with per-topic access control via the shared rbac-api webhook.

The backend is Fastify + TypeScript in a single container image that also serves the SPA: the catalog service, the GitLab gateway (/api/configs, /api/systems), and the graph-to-configuration compiler, with JSON-Schema validation before anything is committed.

Beyond a single flat diagram, a design supports layers, annotations, includes and shared references — so a large system can be composed from reusable pieces rather than one enormous canvas — and a control graph distinct from the media graph, describing what drives what. Lua automations and role definitions are compiled from the design alongside the media configuration.

A note on preview thumbnails. These are published by input-processor itself, which loads the existing libthumbnail.so through a Rust wrapper rather than running a separate publisher process. They arrive on phrame/input-processor/{uuid}/thumbnail/{input_id}/{output_id} as raw binary JPEG — not base64 — with statistics on the matching stats/ path. Browser clients sniff the magic bytes and render via a Blob URL. They ride a dedicated stats broker, so preview traffic cannot crowd out orchestration messaging.

Status. Architect is under active development and its component coverage grows with the platform; the pages here describe the model and the parts in use rather than a frozen feature list.

Next: The component catalog — where the palette comes from. What a design compiles to — the configuration it produces.