Live 360° production · macOS

Multicam 360°, cut live,
out in 4K.

A vision mixer for immersive shows: twenty-four cameras on one desk, cut and shaded in real time, stitched to a full 4K sphere on the way out. Resolution is not baked in — the desk scales with the cameras you put in front of it, to 8K and beyond.

Download the app All releases Source on GitHub macOS · 768 kB · no vendor software, no account
4Kstitched output
16Kceiling by design
24cameras, live
0vendor software
Resolution

The desk does not know what resolution it is running.

Nothing in the signal path is written for a picture size. Nodes record by stream copy, so they are indifferent by construction. The Mac decodes exactly two cameras — programme and preview — and hands the same four lanes onward in whatever shape they arrived. The sphere is assembled at the far end, and it is the stitcher that decides how big it comes out.

TODAY

4K sphere

Twenty-four Orah 4i, four lenses each at 1920×1440, stitched to a full 4K 360° output. Proven end to end.

TOMORROW

8K and 16K

Put larger sensors in front of it and the same desk carries them. The ceiling is the hardware decoder and the stitcher, never the application.

ANY CAMERA

Not an Orah tool

Orah is what it was built against because that fleet exists and its maker does not. Anything that publishes RTMP fits the same desk.

How it works

The whole show, from the truss to the audience.

Every amber device is a real thing in the van. Tap one.

What it is

The camera outlived its company. The show did not have to.

The Orah 4i is a four-lens 360° camera. Each unit carries two SoCs on consecutive addresses and publishes four RTMP streams at 1920×1440, which a stitching box used to assemble into a 4K sphere. Orah is gone: the update servers are dead, the boxes were unstable, and there is no way to buy a replacement for either.

4idesk replaces the whole chain. It finds the cameras without help, drives them over their own protocol, mixes them on the GPU and hands the result to Vahana — while the Linux nodes record every camera in isolation, untouched.

FINDS THEM

Without Bonjour

Multicast between a wireless client and wired cameras is what access points drop. The wire always knows: an ARP sweep by Orah's own MAC prefix finds every unit, announced or not.

KEEPS THEM

Presence by MAC

DHCP hands a released address to the next camera that asks. A port answering proves something is alive, not that it is the same camera. Identity is the burned-in MAC.

RUNS THEM

Hand-rolled protocol

CamAPI protobuf over WebSocket, written from the wire up — no protoc, no vendor library, no server to phone home to.

The desk

A vision mixer, not a settings screen.

Twelve plus twelve on each bus, and a T-bar you can find without looking.

Philosophy

Everything on this desk was measured, not assumed.

The rules below are not preferences. Each one is what a real camera did on a real bench, written down so nobody has to rediscover it at an event.

Only pictures prove anything

The camera reports success the moment it accepts a command, long before a packet moves. Every state in this app is decided by streams arriving, never by a return code.

Never send what it cannot come back from

This firmware can be wedged by talking to it too fast. Commands are paced, START is asked once, and a camera being worked on is left completely alone.

The recording is sacred

Nodes record every camera ISO by stream copy. Colour, mixing and effects ride the live path only — there is no setting that can contaminate the master.

Say which of the two problems it is

"Camera is not there" and "camera is there but silent" send different people to different places. The interface never merges them.

One state, one place

There used to be four sources for "is it working". They disagreed, and the desk showed a camera on air beside a button offering to start it. Now: one function.

Colour means the same everywhere

Amber is ready, red is on air, green is next. A second meaning for the same colour is exactly what misreads at speed, so it never gets one.

Architecture

One Mac in the gallery, Linux nodes at the cameras.

Twenty-four cameras at ~15 Mbit/s per lens is several gigabits. Nothing of that size goes near the gallery: cameras publish to the node that owns them, and only what is on air crosses the room.

Orah 4i · 4 lenses→ node · MediaMTX→ RECORD · ISO, stream copy one lens per camera→ Mac · VideoToolbox decode→ colour · per camera→ Metal dissolve→ PROGRAM → Vahana
LayerBuilt withWhy
Camera controlCamAPI protobuf / WebSocket Hand-written codec; the vendor's tooling no longer exists.
DiscoveryBonjour + ARP by OUI Bonjour is best-effort. The MAC prefix is not.
TransportMediaMTX 1.20 RTMP ingest and programme republish, config generated per run.
Decode / encodeVideoToolbox Hardware both ways; frames never touch CPU memory.
Mix and colourMetal Dissolve and per-camera correction in one pass.
Recordingnode agent · stream copy ISO per camera, bit-exact, independent of the desk.
The core

Five parts, each owning exactly one fact.

This came out of a bad evening. A change to the multiview broke the colour panel, a change to the colour panel broke the programme monitor, and a change to the decoder took every camera down at once. None of them were hard bugs — they were the same bug. Every window reached into the machinery, and the last one to touch it won.

So the desk has a core now. Data flows one way through it. A window sits at the end and draws; a window never decides.

FLEET · who is out there→ STREAMS · what is publishing→ DECODE · what is decoded→ PICTURES · who sees what→ MIX · what goes to air
FLEET

Who is out there

One control session per camera, held for the show. Knocking has a floor under it that rises — and a camera whose pictures are arriving is on the network, whatever a ping says. Frames are proof; a dropped packet is an opinion.

STREAMS

What is publishing

A set of lenses, never a count. A camera is two boards and routinely publishes two of its four streams — a number cannot say which. One fact, one field: the count is derived from the set, so they can never disagree.

DECODE

What is decoded, and what it costs

Never a reader on a lens nobody publishes. Lenses are added and removed in place, never by rebuilding a source — rebuilding blacks out a picture for three seconds, and that is precisely when somebody has pressed a programme key.

PICTURES

Who sees what

One sink per camera, handed out, never owned by a view. This is the part that did not exist: two windows fought over a single “who am I watching” setting, so opening one blacked out the other.

MIX

What goes to air

The cut happens on the press, before a single process is touched. Colour is applied per camera before the dissolve — grading the composite smears one camera’s correction across the other for the length of every transition.

UI

Renders, decides nothing

The multiview, the colour panel, the monitors and the output window are four designs of one truth. That is the whole point: the same camera cannot be live in one window and black in another.

Each part has its own rules, and its own way back

Every rule was earned by a real failure, so deleting one means knowing which failure it prevented. The rules that can be run are run: the decode planner, the byte splitter that every lens of every camera passes through, and the fleet policies are pure functions with the failures as tests.

orahctl selftest→ 65 checks, 0 failures

And the way back is per part, not per tree: a working state is tagged, and one part can be restored out of it without disturbing the others. Full rules in docs/ARCHITECTURE.md.

Multiview

Four multiviews, any of them on a screen of its own.

Twenty-four 1440×1920 portraits tile properly at 8×3 and nowhere else. Pull one out and the console moves up into the space rather than leaving a hole where a wall used to be — and the strip stays behind, because it is how the window is called back.

Colour

Shading per camera, on the live path only.

ALL puts every camera side by side — each with its own picture, lens keys, a tally across its head, and its own lift/gamma/gain wheel, because a card that can only move exposure is a fader, not a colour corrector. Press a name and the same camera opens in full: four lenses across the top, the lever and the centre-point pad on the left, the three wheels level with them on the right. The ISO recording never sees any of it.

Rig check

Install day is a different job from show day.

Per camera: is it there, is it talking, is it sending.

Tutorial

From a box of cameras to a show, in eight steps.

  1. Power the cameras and open 4idesk

    Nothing to configure. The app sweeps the subnet by MAC prefix and adopts anything answering on port 9989, whether or not it announced itself.

  2. Run the rig check

    Every camera shows one of: not on the network, still booting, ready — press Start, or a count of lenses arriving. A camera someone is working on gets FIX and is left alone.

  3. Number them once

    INSTALL binds a serial to a position. The number follows the hardware from then on, so recordings and scenes line up with yesterday's.

  4. Press Start All

    Each camera is stopped, given its target and started once. About twenty seconds to all four lenses. A START answered UNKNOWN_ERROR means at least one SoC did not come up — that unit needs its power pulled, not another try.

  5. Lay out the multiview

    Pick a variant, switch the free boxes on or off, and send any source to a box with its amber 1–4 keys. Undock it onto the second monitor.

  6. Match the cameras

    In the colour corrector, work camera by camera: lever for exposure, puck for gamma and black, wheels for trim. BYPASS shows what you started from. The recording is not affected.

  7. Assign the keys

    Button order is not camera order. In ⚙ Assign, put them left to right in the order they stand on site, and choose whether keys read a name or a number.

  8. Cut the show

    Preview selects, CUT takes, AUTO dissolves at the rate you set, the T-bar does it by hand. Programme leaves for Vahana; the nodes go on recording every camera clean, whatever happens on the desk.

Change log

What moved, and when.

This page is written from the same designs the application is built from. When the UX or the behaviour changes, both change together — and the entry lands here.