The menu bar app
A popover over whatever you are doing. Every stream with an arm toggle, one Record button, and a mark in the menu bar that tells the truth about the take.
Rheocles.app has no window and no Dock icon. It lives in the menu bar, opens
as a popover, and is a thin client of rheocles-core over the same API you
get. Nothing in it is a feature the API lacks; nothing in the API is a
feature it lacks.
The mark
The mark is the state. It is a template image, so it takes the menu bar’s
colour, and it is drawn from shapes rather than a SwiftUI view — a bare view
as a MenuBarExtra label renders with no colour at all, which Sonocles paid
to learn.
| state | the mark |
|---|---|
| idle, nothing armed | the whole mark at 40 % |
| something armed | the strokes in outline |
| recording | the strokes filled |
| a stream joined late | a shorter stroke that starts to the right of the bar |
You can read the take from across the room without opening anything, and — the case the ochre exists for — you can see from across the room that six cameras are still armed.
The popover
Streams. Every camera, microphone, display and system audio, each with an arm toggle. Armed rows are ochre. Audio streams show a level meter while armed. Windows are listed only when Show windows is on in settings.
Preview, on demand. One stream at a time, behind a button — not a wall of
thumbnails. Each look is one GET /preview/{stream}: a single JPEG grabbed by
a polite second opener that never disturbs an armed or recording take, or,
for an audio stream, the peak level that drives the meter. Nothing is
captured when nobody is looking, and one preview runs at a time.
Record / Stop. One button. Record is POST /record: create and start
together. The current take’s name and elapsed time sit beside it, and under
it, when the armed set allows one, the Also save a single
file checkbox.
After stop. The outcome line — complete or incomplete with its
reason — with an Open in Finder button for that take’s
folder; a Single file · combined.mov line when the take asked for one;
and the recent takes, folded, each with its own Open in Finder.
Settings. Output root and codec (HEVC or ProRes 422, one global setting)
— PATCH /settings, and the root will not move while a take is active;
Show windows; and the bearer token, shown as a pairing code with a rotate
button that is POST /token/rotate. The output root has an Open in Finder
button too.
Open in Finder
A folder glyph, in Aegean, wherever a destination is shown:
| beside | reveals | the call |
|---|---|---|
the outcome line after complete or incomplete |
that take’s folder | POST /takes/{id}/reveal {} |
| each recent take | that take’s folder | POST /takes/{id}/reveal {} |
the Single file · combined.mov line, once complete |
the file, selected in its folder | POST /takes/{id}/reveal { "path": "combined.mov" } |
| the output root, in settings | the root | POST /reveal {} |
The app never opens the Finder itself. Every button is a call to the
daemon, which does the revealing on its own Mac — the same call
Pteroprompter makes from a browser page, which cannot open the Finder at
all, and the same one the NativePHP app makes. One implementation, on the
one process that has the files. The button does nothing visible when the
take folder is gone, because the daemon answers 404 and there is nothing
to show; and it does nothing at all against a daemon older than this
feature, which answers 404 not_found for the route — see
Troubleshooting.
Also save a single file
A checkbox in the take bar, beside Record, labelled Also save a single
file with combined.mov · no re-encode after it. It is the daemon’s
settings.combine: ticking it is PATCH /settings { "combine": true }, so
it is remembered across launches and shared with every other front end on
the same daemon, and every take from then on is created with the daemon’s
default until you untick it.
It is shown only while at most one video stream is armed. Arm a second
display or camera and the checkbox goes — hidden, not greyed — because a
passthrough mux has no single file to make from two pictures. Disarm one
and it comes back, still ticked if it was. The setting is not changed by
hiding it; a take recorded while it is hidden is created without a
combined file and the daemon says so in warnings.
After stop, the take bar shows Single file · combined.mov with a pulse
while the daemon is writing it (combined.state is pending), a green
dot and an Open in Finder button when it is complete, or the reason in
oxide when it failed. A finished take that has no combined file and at
most one video stream — one recorded with the box unticked, or one whose
combine failed — shows a Combine now button instead, which is
POST /takes/{id}/combine. The take’s own outcome line does not change on
a failed combine; the per-stream files are the take. What the file is and
is not — one video track, every audio stream as its own track, no
re-encode, no mixdown — is on Recording a
take.
The daemon
The app bundles rheocles-core and launches it if nothing answers on 7447;
if something does, it uses what is running. Two front ends on one machine —
the menu bar app and the NativePHP app, or a future Pteroprompter — share one
daemon. There is no LaunchAgent in the MVP: the daemon lives as long as
something is talking to it.
The daemon’s output root, codec and combine default live in settings.json
beside the token. Launching rheocles-core --output-root <path> overrides the
persisted root for that run, and --settings-file <path> points it at a
different settings file altogether — the way to point a test at a scratch
volume without touching your settings.
Reviewing the UI without a screen
Rheocles.app/Contents/MacOS/Rheocles --render-preview ./previewsrenders every popover state to PNG offscreen, as Sonocles does, so a change can be reviewed from a build log. AppKit-backed controls do not rasterise this way; anything in the popover that needs to appear in a preview is drawn from shapes.
Style
The app follows docs/BRAND.md and this site, not Pteroprompter, and it is
not a dark theme: the same limestone ground and ink text as this page,
aegean for the signature, ochre armed, oxide recording, olive
complete, script for a value it does not have. The only dark surface is a
code or data block, as here.