user manual · v0.1.0

Everything Fhenix Play does, in one place

Fhenix Play is a streaming studio: compose cameras, screens, and IP feeds, polish them with on-device AI, and send the result everywhere at once — a system virtual camera, an RTMP stream, and a local recording. Control the show from an iPad or iPhone, and let your audience tip and bid with amounts that stay encrypted on-chain, powered by Fhenix CoFHE.

windows 10 / 11 macos 13+ ipados & ios 17+ companion powered by fhenix cofhe
The Fhenix Play main window: Program view, preview strip, layouts strip, filters dock
The studio. Output controls on the left, the Program stage and preview strip in the center, dock panels on the right.

01Overview

Fhenix Play sits between your real cameras and the places your video goes. You stage up to four sources, dress the picture up (color, AI effects, overlays, full-scene layouts), and publish the finished Program as a system virtual camera called “Fhenix Play” — and, at the same time, as a live RTMP stream and a local recording.

What it does, at a glance

CapabilityWhat you get
Multi-source switchingFour slots for webcams, screens/windows, RTSP feeds, video files, a demo loop, or your iPad/iPhone camera. Click a tile to take it to Program with a cut or fade.
LayoutsFull-screen scenes written in HTML — breaking news, interview split, picture-in-picture — with live video boxes mapped to your slots.
Transforms & colorPer-source mirror, flip, rotate, zoom; hue/saturation/exposure/contrast/temperature grading; one-click color match to a reference camera.
AI filtersBackground blur / replace / remove, face privacy, auto-framing, live captions, hand-gesture triggers, and a voice changer — all on-device.
Overlays & pluginsText, images, web pages, and sandboxed HTML plugins — in front of you or behind you.
OutputsVirtual camera for Zoom/Meet/Teams/OBS, RTMP streaming to any platform, and local MP4/MKV recording — independently, in parallel, hardware-encoded.
Companion appA native iPad/iPhone app on your LAN: live Program monitor, multiview, switching, layout control, telestration with Apple Pencil, tip moderation, and the device camera as a wireless source.
Confidential interactionsEncrypted-bid rounds, viewer perks, and confidential super-chat tips on Fhenix CoFHE — amounts stay encrypted end to end.

02Installation

Fhenix Play ships as a signed installer per platform — an .exe on Windows, a .dmg on macOS. The companion app installs separately on your iPad or iPhone.

Windows Install the app

  1. Download and run the installer

    Grab Fhenix Play-0.1.0-build<N>-x64.exe and double-click it. If Windows shows a SmartScreen notice, click More info → Run anyway.

  2. Allow the install

    Windows asks for administrator permission — the installer registers the virtual-camera driver system-wide. Click Yes.

  3. Done — the camera is registered automatically

    The Fhenix Play camera is immediately visible to Zoom, Meet, Teams, and OBS. Launch the app from the Start menu; Windows asks for camera/microphone access the first time you load a source.

macOS Install the app

  1. Open the disk image

    Download Fhenix Play-0.1.0-build<N>-arm64.dmg, open it, and drag Fhenix Play.app to Applications. The app is signed and notarized.

  2. Approve the camera system extension (one time)

    The first time you start the virtual camera, macOS shows “System Extension Blocked.” Click Open System SettingsPrivacy & Security, allow the Fhenix Play extension, and enter your password if asked.

  3. Grant camera & microphone access

    Both are required: the camera to compose your picture, the microphone for on-device captions and audio in your stream/recording. Audio is never uploaded anywhere.

Removing the app on macOS. Dragging the app to the Trash does not remove the camera extension. Turn the extension off first in System Settings → Privacy & Security, then delete the app.

iPadOS / iOS Install the companion

Install Fhenix Play Companion from the App Store (or a TestFlight invite) on any iPad or iPhone running iPadOS/iOS 17 or later. Pairing and everything else the companion does is covered in §12.

System requirements

PlatformMinimum
WindowsWindows 10 or 11 (64-bit). A modern multi-core CPU is recommended for AI filters; an NVIDIA/Intel/AMD GPU enables hardware encoding.
macOSmacOS 13 Ventura or later, Apple Silicon or Intel. VideoToolbox hardware encoding is used automatically.
iPadOS / iOSiPadOS or iOS 17+, on the same local network as the desktop.

03Quick start — live in five steps

  1. Add a source

    In the preview strip, click + Add source on an empty tile and pick your webcam (or a screen, an RTSP feed, a video file, or the demo loop).

  2. Take it to Program

    Click the tile. It moves to the large Program view with a red PGM badge — this is what every output sends.

  3. Dress it up (optional)

    Open the right-hand dock and try Filters → Background for a blur, add a lower-third from Overlays, or take a full scene from the Layouts strip.

  4. Start an output

    In the left Output column, click Start virtual camera — and/or set up Live stream / Recording right below it.

  5. Select the camera in your meeting app

    In Zoom/Meet/Teams, open camera settings and choose Fhenix Play. You’re on.

Go further in five more minutes. Pair the iPad companion to switch and draw from the couch, or open the Interaction Studio to let viewers tip with encrypted amounts.

04The interface

The window has three regions.

RegionContains
Left — OutputOutput resolution picker, the virtual camera start/stop with live status, and the Live stream / Recording tabs with their encoder settings.
Center — StageThe big Program view (what all outputs send), the Transform bar, the four-slot preview strip, and the Layouts strip with the take-transition control.
Right — DockAn icon rail that switches panels: Overlays, Layout, Camera color, Filters, Blockchain, iPad companion, and Settings.
The three regions: Output column on the left, Program stage in the center, Filters dock panel on the right
Left to right: the Output column (virtual camera + stream/record), the stage with the demo loop on Program, and the dock open on Filters. The icon rail on the far right switches dock panels — it shows a red badge when a companion pairing request is waiting.

05Sources & the preview strip

The preview strip holds up to four sources. The tile on Program (red border, PGM badge) is what your outputs send; click any other tile to take it with the transition you picked (cut or fade — the control lives at the right end of the Layouts strip, and applies to every take).

Source types

SourceNotes
Webcam / capture deviceAny camera the OS sees, captured at your output resolution.
Screen or windowPick a display or a single window from live thumbnails.
RTSP feedIP cameras and NVRs: paste an rtsp:// URL and give it a name. Runs over your network — great for wired multi-angle setups.
Video fileA local mp4 / webm / mov, looped.
Companion cameraYour iPad or iPhone camera, published wirelessly from the companion app (§12).
Demo loopThe built-in branded placeholder — handy for testing and as a “be right back” card.
The source picker modal over the studio: cameras, screens, windows, RTSP, file, demo loop
+ Add source opens the picker: devices, screens and windows with live thumbnails, RTSP, files, and the demo loop. If no devices appear, click Grant camera access and approve the OS prompt.

Per-tile controls

ControlEffect
Click tileTake the source to Program (cut or fade, per the take-transition control).
REFMark this source as the color-match reference (green border). Other cameras can be graded toward it in one click from the Camera color panel.
Clear the source from the slot.

Output resolution

The Resolution picker at the top of the Output column sets the canvas every output shares — from 320×240 up to 4K UHD, filtered to what your camera supports.

Change resolution before going live. Some apps (notably OBS) latch the camera resolution when they first connect. If you change it mid-call, re-add “Fhenix Play” as the source in that app.

06Transforms

The Transform bar above the preview strip adjusts the geometry of the active source. Each source keeps its own settings.

ControlRangeNotes
Mirroron / offFlip left↔right — the natural “selfie” view.
Flipon / offFlip top↔bottom.
Rotation0° / 90° / 180° / 270°For sideways or mounted cameras.
Zoom1.0×–4.0×Punch in to crop tighter.
ResetBack to defaults.

The preview tile mirrors your transform too, so the framing you see is the framing you send.

07Camera color

The Camera color dock panel grades the active source. Everything is neutral by default and costs nothing until you move it.

ControlRangeUse
Hue−180°…+180°Shift overall color.
Saturation0…200%0 = grayscale, 100 = neutral.
Exposure−3…+3 EVBrighten or darken in stops.
Contrast50…150%Punch or flatten.
Temperature−1…+1Cooler (blue) ↔ warmer (red).
Multi-camera trick: color match. Mark your best-looking camera REF in the preview strip, then grade any other camera toward it from this panel — a multi-camera setup starts looking like one shoot.

08Filters & AI effects

The Filters dock panel is a stack of collapsible sections; an active filter’s section stays open so you can always see what’s running. Everything runs on-device — your video never rides a third-party cloud.

Background — blur, replace, or remove

Segments you from your room in real time.

  • Blur — keep the room but soften it; a strength slider controls the amount.
  • Replace — drop in a solid color behind you.
  • Remove — make the background transparent so “Behind” overlays show through.

Edge softness and edge cutoff fine-tune the silhouette. The first enable has a one-time model load.

Face privacy pixelation live on Program with the Background filter section open in the Filters panel
AI filters live: face privacy (pixelate) on the subject, with the Background section open in the Filters panel — active sections stay expanded so you can see what’s running.

Face privacy

Obscures detected faces in three modes — Pixelate, Blur, or Redact eyes (a black bar) — with sliders for block size / strength, padding, and (for the eye bar) vertical offset. Protects bystanders and camera-shy guests without touching the rest of the frame.

Auto-frame

Tracks your face and gently pans/zooms to keep you centered. One Tightness slider goes from a wide head-and-shoulders shot to a tight face crop.

Live captions

On-device speech-to-text (Whisper) burned onto the Program output. Choose your microphone, language (auto-detect or fixed), and model size — tiny (~75 MB, fastest), base (~150 MB, recommended), or small (~500 MB, best quality). Models download on first use; a status line shows listening/transcribing state.

All transcription happens locally. Audio never leaves your machine.

Gestures

Trigger actions with hand poses detected on the active source. Bind any of seven gestures — ✋ open palm, ✊ fist, 👍 thumb up, 👎 thumb down, ✌️ victory, ☝️ point up, 🤟 ILY — to actions like toggling an overlay or cutting to another source. Held gestures fire once, then cool down.

Voice changer

Transforms your microphone and exposes it as a virtual mic other apps can select. Presets: Anonymize, Deeper, Higher, and Custom (a pitch slider in semitones).

Routing note. To send the transformed voice into a meeting app, point the Output at a virtual audio cable — VB-CABLE on Windows or BlackHole on macOS (the panel links to a download) — then pick that cable as your microphone in Zoom/Meet/Teams.

09Overlays

The Overlays dock panel stacks graphics on top of (or behind) your video. Add as many as you like; drag to reorder; toggle each with its eye icon.

Overlay types

TypeWhat it is
TextA styled string — font, size, bold/italic/underline, color, stroke, shadow.
ImageA local image file or URL (logos, frames, badges).
URLA live web page rendered in place.
PluginAn HTML plugin overlay — animated, parameter-driven. See §14.

Positioning & behavior

ControlPurpose
Position / SizePlace and scale the overlay on the frame.
OpacityBlend it with the video.
Layer: Front / BehindFront draws over you; Behind draws between your background and you — the app turns on person segmentation and re-draws you on top.
Show on slot“Always,” or only when a specific source is on Program.
TTLAuto-hide after N seconds (0 = stays until you remove it).
The “Behind” effect. Tick Behind on any overlay to sit “in front of” a graphic — no plugin code or mask handling needed.

Export & import

The panel’s Export / Import buttons save your whole overlay set (including image data) as one file you can move between machines or share.

10Layouts — full scenes in HTML

A layout is a full-screen scene that takes over the whole Program: a breaking-news frame, an interview split, picture-in-picture. Layouts are plain HTML pages with transparent boxes where live video shows through — each box maps to one of your preview slots. Anyone who can write a web page can design a broadcast.

The Interview layout live on Program: two camera boxes with name plates, with the Layout panel open
The Interview bundled layout on Program — two live camera boxes with name plates. The Layout panel on the right edits its boxes and text.

Taking a layout

The Layouts strip sits under the preview slots:

  • Browse layouts… opens the picker with previews of every installed layout. Bundled scenes: Breaking News, Interview, Presentation + Cam, Presentation + Round Cam.
  • Your selected layout stays parked as a chip in the strip even after a source takes over Program — click the chip to bring it straight back. Live = red chip with a dot.
  • The Cut / Fade control with its duration slider sets the take transition — it applies to every take, slots and layouts alike.
  • Reload re-reads the layout file from disk — the authoring loop while you edit its HTML.

The Layout panel — boxes & live text

With a layout on Program, open the Layout dock panel to control it at runtime:

  • Box sources — box N shows slot N by default; remap any box to a different slot or to no source. Per-layout, persisted, re-applied automatically on the next take.
  • Elements — the layout’s text fields (live badge, show name, headline, sub-headline, ticker…) as live editors. Changes are pushed into the running page instantly, without touching the HTML file.
Breaking News live with the Layout panel open: box sources and element text editors
The Layout panel while Breaking News is live: box-to-slot mapping on top, the scene’s editable text elements below. Note the red Breaking News chip in the strip — the layout is on air.

Create your own — a working example

A layout is a normal web page — CSS animations, web fonts, JavaScript, fetch() all work — plus a handful of data-fhx-* attributes the app reads. Drop a top-level .html file into Documents / Fhenix Play / Layouts (or a folder with an index.html plus its own assets), open Browse layouts…, and it’s there — the picker rescans the folder every time it opens. The tile’s name comes from the page’s <title>.

On first run the app seeds that folder with the four bundled scenes and a LAYOUT-GUIDE.md — they’re editable copies, yours to dissect (the app never overwrites your changes). Here is a complete two-camera scene with an editable headline and name plates:

Documents/Fhenix Play/Layouts/side-by-side.html
<!doctype html>
<html><head><meta charset="utf-8"/>
<title>Side by Side</title>   <!-- the name shown in the picker -->
<style>
  html, body { margin:0; width:100vw; height:100vh;
               background:transparent; overflow:hidden; }  /* video shows THROUGH the page */
  .bg   { position:absolute; inset:0; background:linear-gradient(160deg,#0c1222,#14263a); }
  .cam  { position:absolute; top:16vh; width:42vw; height:60vh;
          background:transparent;                    /* boxes must stay transparent */
          border:0.5vh solid #0ad9dc; border-radius:1vh; }
  .plate{ position:absolute; left:0; bottom:-5vh; padding:0.9vh 1.8vh;
          background:#0ad9dc; color:#001623; font:600 2.6vh/1 system-ui,sans-serif; }
  .headline { position:absolute; left:0; right:0; top:4vh; text-align:center;
              color:#fff; font:700 5vh/1.2 system-ui,sans-serif;
              text-shadow:0 0.4vh 1.2vh rgba(0,0,0,.55); }
</style></head><body>

  <!-- full-bleed background: on its OWN element, marked as backdrop —
       the app punches transparent holes into it wherever the boxes are -->
  <div class="bg" data-fhx-backdrop></div>

  <!-- editable from the Layout panel; this text is the default -->
  <div class="headline" data-fhx-text="headline" data-fhx-label="Headline">Tonight’s show</div>

  <!-- video boxes: the NUMBER binds the box to that preview slot -->
  <div class="cam" style="left:4vw"  data-fhx-box="1">
    <div class="plate" data-fhx-text="name-left" data-fhx-label="Left name">Host</div>
  </div>
  <div class="cam" style="right:4vw" data-fhx-box="2">
    <div class="plate" data-fhx-text="name-right" data-fhx-label="Right name">Guest</div>
  </div>

</body></html>

Save, take it from Browse layouts…, and cameras from slots 1 and 2 appear in the two frames. The headline and both name plates show up as text fields in the Layout panel — no JavaScript needed. From here the loop is: edit the file → ⟳ Reload in the strip → Program updates in place.

Attribute reference

AttributeMeaning
data-fhx-box="N"Marks the element as a video box bound to preview slot N (1–4). The video renders underneath the page, so the element — and everything covering it, including <body> — must have background: transparent. Borders, corner accents, and children (like the name plates above) composite on top of the video. An empty slot leaves your page’s own styling visible, so give boxes a styled backdrop or border.
data-fhx-backdropPut full-bleed backgrounds on their own element with this attribute instead of on <body> — the app automatically punches transparent holes into it wherever the boxes are, and the holes track boxes that move or resize. Avoid overlapping two boxes over the same backdrop.
data-fhx-fitHow video fills the box: cover (default — fill, cropping the excess) or contain (letterbox so nothing is cropped — right for screen shares and slides).
data-fhx-shape="circle"Clips the video to the ellipse inscribed in the box — a true circle when the box is square (size both axes in the same unit, e.g. 26vh). Draw the ring frame yourself with border-radius: 50%; backdrop holes become circular automatically. See pip-circle.html.
data-fhx-text="name"Makes the element’s text an editable field in the Layout panel. The element’s own text is the default; panel edits are applied to the running page instantly (the app sets its textContent), remembered per layout, and re-applied on the next take and after Reload.
data-fhx-labelThe friendly name the panel shows for that field (falls back to the data-fhx-text name).
Box rules worth knowing. The data-fhx-box value must be a number ≥ 1; if two elements claim the same number, the first in the document wins. Box positions are measured live (CSS transforms included), so a box can move or resize with an animation and the video follows within about half a second. The slot’s own settings — mirror/rotate/zoom, color grade, color match — still apply inside the box; single-source vision filters (background blur, face pixelate, auto-frame) don’t run inside layout boxes.

Parameters from JavaScript — window.fhenixLayout

For plain on-screen text you never touch JS — the host writes panel edits straight into the tagged elements. The API exists for JS-driven content: tickers, charts, anything that must rebuild when a parameter changes.

interface FhenixLayout {
  readonly apiVersion: 1;
  /** Current panel overrides, keyed by data-fhx-text name. */
  readonly params: Readonly<Record<string, string>>;
  /** Subscribe to panel edits. Returns an unsubscribe fn. */
  onParamChange(cb: (params: Readonly<Record<string, string>>) => void): () => void;
}

To expose a parameter that isn’t literal on-screen text (a ticker’s source string, a chart symbol), park it on a hidden element — it still becomes a panel field:

<!-- a panel field with no visible element of its own -->
<span data-fhx-text="ticker" data-fhx-label="Ticker (• separated)"
      style="display:none">Welcome to the show • Stay tuned</span>

<script>
  const api = window.fhenixLayout;
  function apply(p) {
    if (p.ticker !== undefined) rebuildTicker(p.ticker.split("•"));
  }
  apply(api.params);          // saved overrides, if any
  api.onParamChange(apply);   // live edits from the Layout panel
</script>

This is exactly how breaking-news.html feeds its ticker — read it for the full pattern.

Design size, animation & performance

  • Design at 1920×1080 and use vw/vh/% units. The page renders at the actual program resolution, and viewport units keep everything proportional. Avoid fixed px for anything that must scale.
  • Keep continuous animations localized. The app captures only what changed each frame, but as one merged rectangle — a ticker strip along the bottom costs ~2–5% of the frame, while a pulsing dot top-left plus a ticker bottom-right unions into a near-full-screen repaint 30×/s.
  • Use discrete timing for slow ambience. step-end / steps(n) easing repaints only when the value jumps — breaking-news.html blinks its LIVE dot at 2 repaints/s instead of 30; interview.html drifts its full-screen gradient in 48 steps. A smoothly-easing full-screen animation is the single most expensive thing a layout can do.

External data

fetch() works from layouts (see the ETH price widget in pip-presentation.html). The page’s origin is fhenix-layout://local, so APIs that send Access-Control-Allow-Origin: * work as-is, and the app CORS-unlocks a short allowlist of popular data APIs (e.g. CoinGecko). Always wrap fetches in try/catch and keep a fallback value — a network hiccup on stage should degrade gracefully, never blank your scene.

When something’s off

  • A box shows my page background, not video — that slot is empty (put a source in it), or the box/an element above it isn’t transparent.
  • A box isn’t detected — the data-fhx-box value must be a number ≥ 1 on a visible element; duplicate numbers are ignored (first in the document wins).
  • The layout tile shows ⚠ — the page failed to load or crashed; hover the tile for the error, fix the HTML, then Reload or re-take.
  • Fonts or images missing — use relative paths next to your HTML (put the layout in its own folder with index.html + assets) or data: URIs; remote webfonts load fine when the network is up.

11Outputs — virtual camera, stream, record

Everything you compose goes out through up to three outputs at once, all fed by the same Program frame: the system virtual camera, an RTMP live stream, and a local recording. Each starts and stops independently.

The virtual camera

Click Start virtual camera in the Output column. The status line shows:

StatusMeaning
IdleNot started.
Starting…Bringing the device up. On macOS, if approval is pending you’ll see buttons to open System Settings and retry.
LiveBroadcasting at the chosen resolution and frame rate.
ErrorShows a code/message — most often the macOS extension still needs approval.

With the camera live, pick Fhenix Play in your app:

Zoom → Settings → Video → Camera Google Meet → ⚙ → Video → Camera Teams → Settings → Devices → Camera OBS → Add → Video Capture Device FaceTime / Discord → camera picker
macOS keeps the camera alive. A small helper keeps the virtual camera available to apps that are mid-call even if you close the Fhenix Play window, so your meeting isn’t cut off.

Live stream (RTMP) & recording

The Live stream tab: RTMP URL, stream key, encoder, resolution, fps, bitrate, microphone
Live stream — point it at any RTMP ingest (YouTube, Twitch, your own server).
The Recording tab: folder, container, rate control, quality, encoder, microphone
Recording — local MP4/MKV with constant-quality or fixed-bitrate encoding.

Streaming

  1. Server URL + stream key

    Paste your platform’s ingest URL (rtmp://…) and stream key. The key is stored in the OS keychain, write-only — it never appears in config files or logs, and the field only ever shows that a key is saved.

  2. Pick encoder & quality

    Auto selects the best hardware encoder found on your machine — NVIDIA NVENC, Intel Quick Sync, AMD AMF, or Apple VideoToolbox — with x264 (CPU) as the fallback. Set resolution (source / 1080p / 720p / 480p), FPS, bitrate, and keyframe interval (2 s is what most platforms ask for).

  3. Audio

    Choose the microphone to send, and use Audio sync offset if your voice leads or trails your lips (+ if you hear words before lips move).

  4. Start streaming

    The status line shows the live timer, encoder fps, bitrate, and any dropped frames.

Recording

  • Folder — where files land (Open jumps to it).
  • ContainerMP4 (fragmented), which survives a crash mid-recording, or MKV.
  • Rate controlConstant quality (CQ slider — lower = better, bigger file) or a fixed bitrate; plus the same encoder/resolution/fps/microphone choices as streaming.
Everything runs in parallel. Stream, record, and run the virtual camera at the same time — captions, overlays, layouts, and telestration from the iPad are in all of them, because they’re all the same Program frame.

12iPad & iPhone companion

Fhenix Play Companion turns an iPad into your control room — and an iPhone into a pocket monitor and wireless camera. It pairs over your local network; nothing routes through a server.

  • Live Program monitor plus a four-slot multiview, in real time
  • Take any slot or layout to Program with a tap — cut or fade
  • The iPad or iPhone camera becomes a wireless source on stage
  • Telestration: draw over the live Program with Apple Pencil — freehand, arrows, and shapes
  • Moderate confidential tips before they hit the stream
iPad companion: live Program with telestration, sources multiview, layout chips, dashboard panel
The iPad companion mid-show: live Program with a telestration arrow, the multiview Sources strip with Cut/Fade, layout chips, and the Dashboard panel on the right.

Enable the companion on the desktop

Open the iPad companion dock panel (tablet icon in the rail) and tick Enable iPad companion. The desktop starts listening on your LAN (port 47800 by default) and advertises itself over Bonjour so devices can find it by name.

Pairing — two ways

Option A

Scan the QR code

On the desktop click Pair iPad…; on the device choose Scan pairing QR code and point the camera at the screen. Done — the QR carries host, port, and a secret pairing token.

Option B

Request approval

No camera needed. The device lists desktops it found on the network; pick yours and it shows a 6-digit code. The same code appears in the desktop’s companion panel — compare, then Approve.

The desktop pairing modal showing the QR code
Pair iPad… shows the QR. New code rotates the pairing token and unpairs the current device.
The companion panel with a pending pairing request: device name, 6-digit code, Approve / Reject / Block
An incoming pairing request — the rail icon gets a red badge, never a popup. Match the code with the device, then Approve, Reject, or Block.
The iPad pairing screen: scan QR or request approval from a discovered desktop
The device side of pairing: scan the QR, or pick a discovered desktop and Request approval — the 6-digit code shown here must match the one on the desktop.
One device at a time. Pairing a new device displaces the old one, and New code in the pairing modal revokes access entirely. Devices you Block can’t ask again until you unblock them in the panel.

Monitor & switch

  • Program monitor — the live Program, streamed to the device with sub-second latency. The header shows the desktop’s name and connection health (round-trip time), plus the Disconnect control.
  • Sources multiview — all four slots as live tiles (not stills). Tap one to take it; the Cut / Fade picker sets the transition; the on-air tile is tallied red.
  • Layout chips — every installed layout, right under the sources. Tap to take a layout; the live one shows red with a dot. The Layout tab remaps its box sources, exactly like the desktop panel.
  • Dashboard tab — show health at a glance: recording/streaming state with live timers, fps, bitrate, dropped frames, virtual-camera state, what’s on air, the take transition, and tip moderation state.
iPad Layout tab: layout live on Program, box source pickers
The Layout tab with a scene live: take layouts and remap each box — Default, any slot, or No source — from the couch.

Use the device camera as a source

  1. Start publishing

    Tap the camera button in the toolbar and choose Use back camera or Use front camera (iOS asks for camera permission the first time). Switch between them or stop from the same menu, live.

  2. Add it as a source

    On the desktop, the picker now offers your device under Companion camera. Drop it into any slot.

  3. Take it

    It behaves like any other source — transitions, transforms, color, filters, layout boxes all apply. Walk anywhere your Wi-Fi reaches.

Telestration — draw on the broadcast

Enable the pencil in the toolbar and draw directly over the live Program with Apple Pencil or a finger. Strokes are composited into the actual Program output — the virtual camera, the stream, and the recording all show them — and fade out on their own a moment later.

ToolWhat it draws
PenFreehand ink, pressure-sized with Apple Pencil.
LineA straight line from touch-down to release.
ArrowA line with an arrowhead — the classic analyst’s pointer.
RectangleBox an area of the frame.
EllipseCircle a player, a chart, a bug.

A color palette and a Clear button round out the kit. Drawing is buttery on-device (the local echo renders immediately) while the strokes stream to the desktop in real time.

Moderate tips from the couch

With “Hold tips for approval before they hit the stream” enabled in the desktop companion panel, incoming super-chat tips queue up in the device’s Tips tab (the tab shows a count badge). Each card shows the tier, message, and a countdown ring — Approve puts it on stream, Reject drops it, and if the timer runs out it auto-approves (configurable seconds; a held tip is never dropped silently, even if the device goes offline).

iPad Tips tab: pending tip cards with countdown rings and Approve / Reject
The Tips tab: pending super-chats with their countdown, one tap to approve or reject.
The companion running on iPhone in a compact stacked layout
iPhone too. The same app in a compact layout — monitor, switch, and publish the iPhone camera as another angle.
Private by design. The companion is LAN-only: the desktop accepts connections from private network addresses only, the pairing token lives in the OS keychain on both ends and never crosses the network (auth is challenge-response), and video flows peer-to-peer over WebRTC on your own Wi-Fi. There is no cloud relay.

13Confidential interactions

Fhenix Play lets your audience put money where their attention is — through smart contracts computing on fully homomorphic encryption (Fhenix CoFHE). A bid arrives as amount: ▓▓▓▓▓▓ and stays that way on-chain: rivals can’t see it, bots can’t front-run it, and the contract still picks the winner. Everything lives in the Blockchain dock panel.

Connect a wallet

WalletHow it signs
Local keyA private key generated or imported on this machine — stored OS-encrypted in the keychain, never in files or logs.
WalletConnectPair a mobile wallet by QR; signing happens on your phone.
Fhenix PayPair via the Fhenix Pay app; your phone signs.

Pick the network and, if needed, a custom RPC at the top of the panel.

The Interaction Studio

Click Open Interaction Studio… in the Blockchain panel to configure everything in one window, across three tabs:

TabWhat you set up
PerksWhat a winning viewer gets to control: recolor your camera, hide your face, change your background, put a message on stream, show an approved image, activate an overlay plugin, or switch the scene to one of your layouts. Every effect is temporary — each has an on-air duration, and a “Revert all” panic button lives in the panel.
RoundHow viewers win: pick a mode (below), set its numbers, and start the round with your enabled perk catalog attached.
DonationsSuper-chat tiers: the tier thresholds are public; what each viewer actually pays never is.
The Interaction Studio: Perks tab with toggles for what winners control
The Interaction Studio — Perks tab. Each perk is a toggle with its own constraints and on-air duration.

The three round modes

MODE_01

Sealed-bid auction

Highest encrypted bid over the round wins. No one sees rival bids; the leader is revealed only at settlement.

MODE_02

Closest to goal

You set a hidden target amount; the bid that lands closest wins. Every guess stays encrypted until the round settles.

MODE_03

Pay to interact

Anyone clearing a minimum gets the perk. Amounts stay private; no deadline.

Always

Confidential by construction

In every mode, amounts stay encrypted during the round — decryption happens only at settlement, on the threshold network.

Running a round

  1. Configure & start

    Pick the mode in the Studio’s Round tab, fill in its fields, and start the interaction.

  2. Audience joins by QR

    A QR code appears on the Program output. Viewers scan it to open the join page and submit encrypted bids.

  3. Settlement

    When the deadline passes (or you stop the round), it finalizes, decrypts on the threshold network, and the winner’s perk goes live — automatically reverting when its time is up.

Confidential super-chat

Viewers tip with a message; only the tier they cleared is revealed on stream — never the amount. The Tips feed in the Blockchain panel keeps the running list (count, per-tier breakdown, every message) with a status dot showing the on-chain watcher, so you can confirm a donation arrived even when the overlay isn’t showing. Pair it with companion moderation to approve each tip before it hits the stream.

Settings: contracts, permits, diagnostics

  • Network & contracts — factory address, confidential-token address, relay URL, with one-click restore-defaults.
  • Permits — create and select the EIP-712 permit that authorizes the threshold network to decrypt results for your wallet. “Permit not found” errors mean you create one here first.
  • Diagnostics — a live, color-coded log of chain/relay/round activity.
New to Fhenix CoFHE? The confidential token follows the ERC-7984 standard — balances are read confidentially, never as a public number. The round contracts keep every bid encrypted end to end.

14Creating plugins

A plugin is a small HTML/CSS/JS bundle that Fhenix Play renders on an invisible, offscreen page and composites over your video as an overlay. No framework, no build step — just web code and a tiny host API.

This is the practical quick-start. The full contract is in §15 Plugin API reference. For full-screen scenes (rather than overlays), see §10 Layouts — they’re even simpler.

The mental model

Each active plugin overlay is one offscreen browser page. It paints whatever you draw (DOM, Canvas, WebGL, SVG, CSS animation); the host captures each painted frame and draws it over the Program at the position and size you set in the Overlays panel. Your plugin can’t see the video behind it — effects that need the underlying scene (like frosted glass) are done by the host (see blurBehind).

Your first plugin

Create a folder named hello-world in your plugins directory (find it via Overlays → + Plugin → Open folder). Put two files in it:

hello-world/plugin.json
{
  "id": "hello-world",
  "name": "Hello World",
  "version": "1.0.0",
  "apiVersion": 1,
  "entry": "index.html",
  "defaultWidth": 480,
  "defaultHeight": 80,
  "params": [
    { "name": "text", "type": "string", "label": "Text", "default": "Hello, world" }
  ]
}
hello-world/index.html
<!doctype html>
<html><head><meta charset="utf-8"/><style>
  html,body { margin:0; background:transparent; }
  body { display:flex; align-items:center; justify-content:center;
         width:100vw; height:100vh; color:#fff;
         font:600 28px/1 system-ui, sans-serif;
         text-shadow:0 2px 6px rgba(0,0,0,.6); }
</style></head><body>
  <div id="t"></div>
  <script>
    const api = window.fhenixPlugin;
    const el = document.getElementById("t");
    function render(p) { el.textContent = p.text ?? ""; }
    render(api.params);
    api.onParamChange(render);
    requestAnimationFrame(() => api.signalReady());
  </script>
</body></html>

Then in the app: Overlays → + Plugin → Refresh → click Add next to “Hello World.” Edit the Text field and watch it update live.

Bundled examples to learn from

PluginTeaches
glass-lower-thirdParam-driven CSS, fade via a visible boolean, frosted glass with blurBehind.
crypto-tickerNetwork fetch(), deferred updates with commit:"button", many params.
behind-orbitCanvas animation and the Behind layering trick.

Installing & sharing

A plugin is just a folder. To install one, drop it into the plugins directory and click Refresh. To share, zip the folder and send it.

PlatformPlugins folder
Windows%APPDATA%\Fhenix Play\plugins\
macOS~/Library/Application Support/Fhenix Play/plugins/
Don’t hand-type these — Overlays → + Plugin → Open folder opens the correct directory for you.

15Plugin API reference

The complete contract: the manifest, parameter controls, the runtime API, host effects, and the sandbox.

15.1 — plugin.json manifest

Every plugin folder needs a plugin.json at its root. An invalid manifest causes the plugin to be skipped and counted in the picker’s error badge.

FieldTypeDescription
idreqstringStable identifier; must match the folder name. Lowercase, filesystem-safe ([a-z0-9._-]).
namereqstringDisplay name in the picker and overlay row.
versionreqstringSemver. Surfaced only.
apiVersionreqnumberHost contract version. 1 for basic plugins; 2 to use the vision API. A plugin requesting a version newer than the host is refused.
entryreqstringHTML file to load, relative to the folder (e.g. index.html).
descriptionstringShown under the name in the editor.
captureFpsnumber 1–60Paint-capture cap. Default 30 (the host throttles to its own rate anyway).
defaultWidthnumberInitial offscreen width in px (resizable later). Default 640.
defaultHeightnumberInitial offscreen height in px. Default 120.
blurBehindnumber 0–64Frosted-glass blur radius applied to the video behind the overlay (see 15.4).
wantsVisionbooleanWith apiVersion ≥ 2, opt in to per-frame mask/face/pose/gesture data (see 15.6).
paramsarrayEditable parameters (see 15.2).
author / homepagestring / URLOptional credits shown in plugin info.

15.2 — Parameters & controls

Each entry in params renders an input in the overlay editor. Every param has a name (the key in params), a type, an optional label, and usually a default.

TypeOptionsRenders as
stringmultiline:true for a textarea; commit:"button" to apply on Enter/Apply instead of each keystroke (use for expensive work like fetches).Text field / textarea
numbermin, max, step; control:"slider" (needs min+max) for a range slider.Number input or slider
booleanCheckbox
colorDefault as #RRGGBB (any CSS color works at runtime).Color swatch + picker
enumoptions:["a","b",…] (required); default must be one of them.Dropdown
Special convention: a boolean param named exactly visible also gets Play ▶ / Stop ⏹ buttons on the overlay row, for quick show/hide. Your plugin decides what visible does (typically a CSS fade).

15.3 — Runtime API: window.fhenixPlugin

The host injects exactly one global. Nothing else of the host is reachable.

type Primitive = string | number | boolean;

interface FhenixPlugin {
  /** Current parameter values, keyed by manifest `name`. Read-only. */
  readonly params: Readonly<Record<string, Primitive>>;

  /** Subscribe to live param edits. Returns an unsubscribe fn.
      Each call receives the FULL param set (replace, not merge). */
  onParamChange(cb: (params: Readonly<Record<string, Primitive>>) => void): () => void;

  /** Tell the host your first real frame is ready. Frames before
      this fires are suppressed so no half-styled boot frame ships. */
  signalReady(): void;

  /** apiVersion ≥ 2, only when manifest sets "wantsVision": true. */
  onVisionFrame?(cb: (frame: VisionFrame) => void): () => void;
}
MemberBehavior
paramsSnapshot you read on startup to do your first render.
onParamChange(cb)Fires on every edit with the whole param set. Returns an unsubscribe function. A throwing callback won’t break others.
signalReady()You must call this, or the host never captures your overlay. Call it after one or two requestAnimationFrame ticks so fonts/layout settle. Idempotent.
onVisionFrame(cb)Per-frame vision data for opted-in plugins (15.6).

Lifecycle

  1. Host loads your entry in an offscreen page; the preload exposes window.fhenixPlugin.
  2. Your script reads api.params and renders.
  3. You call api.signalReady().
  4. The host starts capturing painted frames and compositing them over the video.
  5. On a param edit, your onParamChange runs with the new full set.

15.4 — Frosted glass: blurBehind

CSS backdrop-filter does nothing in a plugin (there’s no video behind your page to blur). Instead declare blurBehind in the manifest and the host blurs the video region under your overlay before drawing your bitmap on top.

{ "blurBehind": 14 }   // radius in 1080p-reference px
The blur is shaped by your alpha. Where your page is transparent, no blur; where you paint opaque pixels, full blur. So border-radius, clip-path, mask-image and drop-shadows all shape the frosted region automatically. Author your glass card normally (a semi-transparent fill) — don’t add backdrop-filter yourself.

15.5 — “Behind me” layering

To place an overlay between your background and you, you don’t need any code — tick the overlay’s Behind box in the Overlays panel. The host turns on person segmentation and re-draws you on top of the overlay. Use onVisionFrame (below) only if you want effects keyed to the actual mask shape.

15.6 — Vision API (apiVersion 2)

Set "apiVersion": 2 and "wantsVision": true, then subscribe to onVisionFrame to receive the live person mask, face boxes, pose landmarks, and recognized gestures for the active source each frame.

api.onVisionFrame(function (frame) {
  // frame.slotId   : string
  // frame.mask?    : { buffer: ArrayBuffer, width, height }  R8 0..255 person mask
  // frame.faces?   : [{ x, y, w, h }]        source-video UV (0..1)
  // frame.pose?    : [{ x, y, z, visibility }]
  // frame.gestures?: [{ name, score, handedness }]
});

The host only sends vision data to plugins that opted in, and only while segmentation is already running (a Behind overlay, the Background filter, or another vision plugin is active).

15.7 — Sandbox & limits

Plugins run in a locked-down, offscreen page with sandbox, contextIsolation, and nodeIntegration:false. They’re served over a private fhenix-plugin://<id>/ scheme.

CapabilityStatus
HTML/CSS/JS, Canvas, WebGL, SVG, web fonts, CSS animation✅ Yes — it’s a full Chromium page.
Relative files in your plugin folder (./style.css, fetch("./data.json"))✅ Yes (same-origin per plugin id).
Network fetch()✅ Subject to CORS; a small host allowlist eases curated APIs (e.g. CoinGecko for the ticker example).
Node.js, require, filesystem, process❌ None.
Host internals (wallet, virtual camera, chain, other plugins)❌ Only window.fhenixPlugin is exposed.
Reading the program video❌ Not directly — use blurBehind or the vision API.
DevTools on the plugin page❌ Author against the same HTML in a normal browser tab to debug.

Each active plugin overlay is its own renderer process (≈ one browser tab of memory). Captured frames are clamped (long edge ~960 px, ≤24 fps) — fine for an upscaled overlay and easy on the CPU.

16Troubleshooting

The virtual camera doesn’t appear in my meeting app

  • Is the status Live? Click Start virtual camera first.
  • macOS Approve the extension in System Settings → Privacy & Security, then restart the meeting app.
  • Windows Reinstall Fhenix Play, then restart the meeting app — it enumerates cameras at launch.
  • Fully quit and reopen the meeting app after starting the camera.

Resolution looks wrong / source cropped in OBS

  • Set the output resolution before connecting, then re-add “Fhenix Play” as the source in the app that latched the old size.

The companion app can’t find my desktop

  • Both devices must be on the same network (and the same subnet — guest Wi-Fi networks often isolate clients).
  • Make sure Enable iPad companion is ticked and the panel says listening.
  • On the device, iOS asks for Local Network permission the first time — if you declined, enable it in Settings → Privacy → Local Network.
  • Some routers block Bonjour discovery entirely — QR pairing still works, because the code carries the host and port directly.

A pairing request never shows up on the desktop

  • Look for the red badge on the tablet icon in the right-hand rail — requests appear inside the companion panel, deliberately not as a popup.
  • If the device was previously blocked, unblock it in the panel’s blocklist first.

The slot says “Companion camera is not publishing”

  • Publishing is started from the device: camera button → Use back/front camera.
  • If the device shows a camera error, iOS camera permission is missing — the alert’s Open Settings button takes you to the right switch.

The companion’s Program monitor is black

  • Something must be on Program (a source or layout) — take one on the desktop or from the multiview.
  • Check the connection chip in the companion header; if it shows an error, disconnect and reconnect (or re-pair).

Streaming won’t start

  • The button stays disabled until both the RTMP URL and a saved stream key are present — the key must be saved once (it’s write-only after that).
  • If the microphone dropdown shows (missing device), re-pick your mic — the saved one was unplugged.

A filter is slow or won’t start

  • The first use of Background or Captions downloads a model — give it a moment; watch the status line.
  • AI filters apply to the source currently on Program; make sure the right tile is live.

My plugin doesn’t show up / renders nothing

  • Did you click Refresh after adding the folder? Does the folder name match the manifest id exactly? Is plugin.json valid JSON?
  • Did you call api.signalReady()? Until you do, frames are suppressed.
  • Open the same HTML in a browser to spot console errors. Re-add the overlay to pick up file edits (the offscreen page caches).

The voice changer has no output device

  • Install a virtual audio cable (VB-CABLE on Windows, BlackHole on macOS) — the panel links to one — then pick it as the Output and select it as your mic in the meeting app.

17Appendix

File locations

WhatWindowsmacOS
Plugins%APPDATA%\Fhenix Play\plugins\~/Library/Application Support/Fhenix Play/plugins/
Custom layoutsDocuments\Fhenix Play\Layouts\~/Documents/Fhenix Play/Layouts/
App data (config, wallets, models)%APPDATA%\Fhenix Play\~/Library/Application Support/Fhenix Play/
RecordingsThe folder you chose in the Recording tab (Open jumps to it).

At a glance

ItemValue
App nameFhenix Play
Version0.1.0
Virtual-camera name (in other apps)Fhenix Play
Desktop platformsWindows 10/11 · macOS 13+
Companion appFhenix Play Companion — iPadOS/iOS 17+, iPhone & iPad
Companion transportLAN only · default port 47800 · Bonjour _fhenixplay._tcp · WebRTC media
Stream encodersNVENC · Quick Sync · AMF · VideoToolbox · x264
Recording containersMP4 (fragmented) · MKV
Plugin API version1 (basic) · 2 (vision)
ChainFhenix CoFHE · Arbitrum Sepolia testnet · ERC-7984 confidential token

Where to go next

  • Pair the companion§12, five minutes from install to switching scenes off a couch.
  • Design a scene — copy a bundled layout (§10) and make it yours in a text editor.
  • Make a plugin — follow §14, then the full §15 API reference.
  • Run a confidential round — open the Interaction Studio (§13) and let your audience in.