Skip to content

Virtual green screen: segmentation, depth assist, and subject-distance cutoff - #90

Merged
MyNamesEMurray merged 2 commits into
mainfrom
claude/init-lklchz
Jul 27, 2026
Merged

Virtual green screen: segmentation, depth assist, and subject-distance cutoff#90
MyNamesEMurray merged 2 commits into
mainfrom
claude/init-lklchz

Conversation

@MyNamesEMurray

Copy link
Copy Markdown
Owner

What & why

The roadmap's virtual green screen, all three planned stages shipped together:

Stage 1 — background removal on any camera. A Green screen toggle on the main screen (Camera & color section). The phone runs Vision person segmentation per frame (.fast above 30 fps, .balanced at 30, one stateful request per stream for temporal smoothing) and composites the background to BT.709 chroma green (#00B140) in a single Metal compute pass — the bilinear mask upsample doubles as the edge feather. The wire carries ordinary video; no protocol change to decode. Off is free: the hot path with the toggle off is the pre-feature closure verbatim (now a PERFORMANCE.md invariant). Every failure fails open to the uncomposited frame — a Vision hiccup can never blank a stream.

Stage 2 — depth assist + auto chroma key. On Face ID front cameras and LiDAR rear Main cameras, capture swaps to the depth-sibling device and synchronizes a ~15 Hz depth stream that gates the matte (NaN-safe), fixing segmentation's classic failures: posters/monitors keyed as people, low light, held objects. The plugin reacts to the STATE snapshot by auto-adding a pre-configured chroma-key filter to the source — once, by name, respecting later user deletion via a persisted per-source flag — so the phone toggle alone yields a keyed subject in OBS. Degrades silently to segmentation-only when the lens/format can't carry depth (never changes resolution/fps to chase it).

Stage 3 — subject distance. A Subject distance cutoff (0.5–5.0 m, or All) on the app's Live screen and the web panel — same anatomy both surfaces: dragging always sets a real cutoff, tapping the readout returns to All. With one semantic mask covering everyone (per-person masks need iOS 17), the depth cutoff is the only iOS 15 tool that drops people walking by behind you. Rides the existing CONTROL/STATE machinery (green_screen command; supportsGreenScreen/greenScreen/greenScreenDepth/greenScreenMaxDistance fields, spec'd in PROTOCOL.md).

Green screen is SDR-only and forces Standard colour through the same exclusivity pattern the codec uses. Depth delivery deactivates Center Stage/system video effects by iOS policy (documented in-app). STATE caches grow 1 KiB → 2 KiB on the plugin side; the app emits true-only booleans to minimize snapshot growth for old plugins.

Adversarial review pass (three independent lenses) caught and this PR includes fixes for: a cross-queue data race in the depth synchronizer delegate, a double live-reconfigure when switching to HDR/Log with green screen on, substring JSON probes spoofable by Bluetooth mic names (now colon-anchored), a panel/app slider-convention mismatch, and a per-arm Metal shader recompile (now process-wide static).

How it was tested

  • Swift sources parse clean (syntax-check.sh); full type check is CI's macOS job — first compile of Vision/Metal/depth API usage, watch that job.
  • Plugin builds clean under -Wall -Wextra -Werror; the real-HTTP webtest harness passes all checks against the edited web-control.c, and the served panel JS parses (node --check) with the slider logic verified by a value-table smoke test.
  • Needs on-device validation (nothing here can run Vision/Metal/depth): green screen on front + rear cameras, the auto-added filter appearing in OBS, depth assist on a LiDAR phone (Main lens), the Subject distance control from both surfaces, an SDR regression pass with the toggle off, and a thermal soak — plus the formatReport diagnostics dump, which now includes a depth column to answer which resolution/fps combos carry depth per device.

🤖 Generated with Claude Code

https://claude.ai/code/session_015dWUcqAkNNuNELnMPS4RdT


Generated by Claude Code

claude added 2 commits July 27, 2026 09:12
PROTOCOL.md specifies the green_screen CONTROL command (on /
maxDistance, camera-only, SDR-forced) and the STATE fields
(supportsGreenScreen / greenScreen / greenScreenDepth /
greenScreenMaxDistance), including the plugin's add-once-by-name
chroma-key reaction. UI_DESIGN pins the "Green screen" vocabulary and
the subject-distance slider anatomy; PERFORMANCE adds the
off-is-free / on-pays-once invariant with the depth and Center Stage
caveats; the README gains the feature bullet; the roadmap prunes
everything shipped through v1.9.0 and records the deliberate
deprioritization of pairing & encryption.

Release-Skip: true

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015dWUcqAkNNuNELnMPS4RdT
All three planned stages in one feature. The phone segments the person
(Vision, stateful request, .fast above 30 fps) and composites the
background to BT.709 chroma green (#00B140) in a single Metal pass
into pool buffers — capture's own buffers are never written (they race
the encoder's async read), OFF keeps the pre-feature hot path
verbatim, and every failure fails open to the uncomposited frame. On
Face ID front and LiDAR rear Main cameras a synchronized depth stream
(~15 Hz, NaN-safe gate) sharpens the matte and powers a max subject
distance cutoff — the only iOS 15 tool that can drop background
people, since the segmentation mask is one mask for everyone. The
plugin reacts to the STATE snapshot by auto-adding a pre-configured
chroma-key filter (once, by name, on the dial thread per the
set_video_delay precedent, respecting user deletion via a persisted
flag) and the web panel gains the Green screen chip and a
subject-distance slider matching the app's Live row exactly (drag =
real cutoff, readout tap = All). Green screen forces Standard colour
through the settings exclusivity triangle; STATE advertises
supportsGreenScreen/greenScreen/greenScreenDepth/greenScreenMaxDistance
with true-only booleans (old plugins truncate snapshots past 1 KiB;
new caches grow to 2 KiB), and the green_screen CONTROL command
carries on/maxDistance per docs/PROTOCOL.md.

Adversarially reviewed: fixes a cross-queue race in the synchronizer
delegate (outputs now resolved from the callback's own synchronizer),
a double live-reconfigure when picking HDR/Log with green screen on,
substring JSON probes that mic names could spoof (colon-anchored now),
a slider-convention mismatch between panel and app, and a per-arm
Metal shader recompile (now a process-wide static).

Release-Bump: minor
Release-Beta: true

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015dWUcqAkNNuNELnMPS4RdT
@MyNamesEMurray
MyNamesEMurray merged commit e180f9a into main Jul 27, 2026
6 checks passed
@MyNamesEMurray
MyNamesEMurray deleted the claude/init-lklchz branch July 27, 2026 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants