Skip to content

Hance Live: a separate macOS app that registers as a virtual camera #162

Description

@RichardBray

Idea

A separate, small macOS app that reads a camera (e.g. an Elgato), applies a Hance look live, and registers itself as a system capture device — so Camtasia, OBS, Zoom, or Meet can select "Hance" as their camera and get the film look burned in as you record.

This is the OBS Virtual Camera pattern. Not an in-app preview window, and deliberately not a feature of the main Electrobun app.

Why a separate app

The one part of Hance that genuinely wants to be native. Building it separately means:

  • No Electrobun, no webview, no React — a small Swift shell with a settings panel (pick camera, pick look, intensity).
  • The main app doesn't absorb a system extension, its signing requirements, or its release cadence.
  • Shared look library. Looks are JSON in a known presets dir, so you design a look in Hance and pick it in Hance Live. One library, two apps.

Architecture

Link the renderer, don't pipe to it.

packages/wgpu is currently a binary-only crate whose main.rs is 72 lines of stdin/stdout wrapper around an already-public surface:

pub struct GpuRenderer
pub fn new(width, height, raw_params, lut) -> Result<Self, String>
pub fn render_frame(&mut self, input: &[u8]) -> Vec<u8>

Proposed: add a [lib] target exposing GpuRenderer, keep main.rs as the same thin sidecar wrapper. Nothing existing changes behaviour. Hance Live then links the renderer in-process.

This matters more than it looks. The stdin/stdout pipe is an artifact of talking to Bun, not something Live should inherit:

Components:

Piece Language Notes
Capture + settings UI Swift AVFoundation
CMIO Camera Extension Swift/Obj-C macOS 12.3+, system extension in the app bundle, installed via OSSystemExtensionRequest
Effect chain Rust hance-gpu as a lib crate — shared with CLI/desktop, no fork of the look

Performance: not the obstacle

Benchmarked against the current sidecar through the pipe, so these are pessimistic for an in-process design:

Resolution Per frame Throughput
720p 6.4 ms 156 fps
1080p 12.2 ms 82 fps
4K 80.1 ms 12 fps

1080p sits comfortably inside a 33ms budget at 30fps. 4K live is not viable without optimization.

Prerequisite: the sidecar param protocol

renderFrame ignores its params argument (packages/gpu/src/wgpu-renderer.ts:64) — params and the baked LUT are consumed once at init, so changing a setting means respawning the process.

This has now blocked three separate things: live preview, adjusting a look mid-stream, and this feature. Worth fixing in hance-gpu on its own merits, independent of whether Live is ever built. Should be split into its own issue.

Hard prerequisite: signing

System extensions require a Developer ID signature, notarization, and the system-extension entitlement — and a separate app does not make this cheaper.

Today electrobun.config.ts skips both (codesign: hasDeveloperId, no ELECTROBUN_DEVELOPER_ID set) and the .dmg is uploaded by hand. A signed, notarized release pipeline is the real gate on this whole idea.

Open questions

  1. Does Camtasia enumerate CMIO virtual cameras? It should, if it uses the standard macOS capture APIs, but it's the kind of app that may do its own device handling. Unverified.
  2. Does Apple require approval for the system-extension entitlement beyond a Developer ID account?
  3. Two apps means two release pipelines and a version-compatibility question the first time the look format changes. Acceptable, but worth deciding deliberately.

Cheapest first step

Install OBS, enable its Virtual Camera, and check whether Camtasia lists it as a source. If OBS's virtual cam appears, a CMIO extension from Hance would too — question 1 settled in ~10 minutes without writing any code.

Scope note

macOS-only by nature, not by preference: Windows needs an entirely different mechanism (Media Foundation / DirectShow), and none of the CMIO work transfers.

Near-term alternative (shipped)

#163 exports a look as a .cube LUT, usable in Elgato Camera Hub, OBS, Resolve, and Premiere today — no system extension, no signing work. It carries the colour grade but not halation, bloom, aberration, grain, vignette, or camera shake, which no colour→colour mapping can express.

That covers most of the perceived look for a fraction of the effort. Hance Live remains the only way to get the full effect chain live.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — nice to have / somedayenhancementNew feature or requestquestionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions