Aposemati is a free, open-source, Apple-only phone-as-camera tool: the iPhone shoots, the Mac is the viewfinder, shutter and gallery. It is the successor to — and a hard course-correction of — diy-continuity-camera-clone-research.
The name
Aposematism = warning coloration in nature. The literal opposite of camouflage. It is a pun on Camo.
Repo: /Users/levander/coding/aposemati
Spec: /Users/levander/coding/aposemati/docs/superpowers/specs/2026-08-18-aposemati-design.md
🟢 STATUS: THIS IS WORKING SOFTWARE, NOT RESEARCH — 2026-08-18
The first live two-device run captured two photos at 8064x6048 (48.8 MP) from an iPhone 16 Pro to a Mac over a link reported as
awdl0 — direct, written to~/Pictures/Aposemati/2026-08-18/. That is ~17x the pixels Continuity Camera can deliver.68 commits, 219 tests, zero warnings, clean tree on branch
phase0-phase1-link-and-shutter— unmerged and unpushed. Both apps are installed and running on real hardware. Start at aposemati-phase0-phase1-build.The review loop is closed, and the final whole-branch review has now run (2026-08-19, six reviewers, all 68 commits at once) — no finding blocks the branch, and the long-unexplained POSIX 57 during pairing is solved. Two of the three Criticals are real but unreachable through the Phase 1 shutter path, sitting under Phase 2 and Phase 4; the third is the POSIX 57 root cause. Nothing from the review is applied yet — aposemati-whole-branch-review.
🚶 The last untested product claim is the walk to the spot where Camo drops, with the apps. Phase 0 proved the probe holds
awdl0there at 156 Mbps — but that was two Macs moving zeros.
🟢 PHASE 2 IS COMPLETE — live preview, 2026-08-25
33 commits, 418 tests, both apps building, complete at
c29f84d. JPEG frames from the phone through a 12-rung quality ladder, fragmented into QUIC datagrams, reassembled against a 200 ms deadline on the Mac, decoded and displayed. A lost fragment costs exactly one frame, never the stream — measured on two real QUIC ends, not asserted. Start at aposemati-phase2-live-preview.⏸️ The verdict is deliberately blank pending hardware.
docs/superpowers/phase2-results.mdis a measurement gate: the two readings that decide whether JPEG-per-frame is enough — the buffer dimension the phone delivers, and datagram lossponawdl0— need two devices, and no device build was permitted. One reading decides two verdict rows at once: 4032×2268 → 240 fragments / 69.0 Mbps (passes), 1920×1080 → 408 fragments / 117.4 Mbps, which fails a derived 50%-of-throughput bar.🔴 Hardware checklist item 1 is not preview at all — it is Phase 1’s stills.
AVCaptureVideoDataOutputnow joins the capture session unconditionally, so 48 MP + ZSL must be re-verified with it attached before anything else is measured.
Decisions made 2026-08-18
| Decision | Value |
|---|---|
| Name | Aposemati |
| Licensing | Open source, public repo, free |
| Platforms | Apple only — no Windows, Android or Linux |
| Ambition | A serious personal tool, not a toy |
| v1 scope | Full-sensor 48MP stills + on-device video recording |
| Roles | iPhone shoots. Mac is viewfinder / shutter / gallery. |
| Virtual camera | Deferred to phase 7 |
| Defining constraint | Off-router direct transport |
| Use case | Both devices together, far from the router |
The defining constraint, restated
The product is the transport. Both devices are in the same place, far from any access point. Anything that hairpins through a router inherits Camo’s failure mode. This thesis came from the original brief and survived the invalidation of that brief’s Wi-Fi Aware architecture.
Architecture
Four channels, not one stream
Never stream the thing you are keeping
Camo streams video to the Mac and records the stream, so recording quality is bounded by transport quality. Aposemati records where the sensor is and ships the file afterward.
| Channel | Payload | Latency | Delivery | Connection |
|---|---|---|---|---|
| Preview | ⚠️ as built: 1080p JPEG per frame, 12-rung ladder (HEVC/H.264 is the open question) | Critical | Droppable | ⚠️ as built: its own connection to its own listener on a separate port, datagrams — not A |
| Control | Shutter, focus point, settings, framing | Low | Guaranteed | A — stream |
| Stills | Full-res HEIF (see the capability matrix) | Irrelevant | Guaranteed | B — stream |
| Video | Recorded on-device at full quality, transferred after | Irrelevant | Guaranteed | B — stream |
Corrected during design: two connections, not one
The original design put all four channels on one QUIC connection. QUIC eliminates head-of-line blocking between streams, but all streams on a connection share one congestion controller, and Network.framework exposes no cross-stream priority — every function in
quic_options.hwas enumerated. A multi-megabyte still would contend with the preview’s congestion window and reproduce the exact “Camo is laggy” failure this project exists to fix.Two connections give independent congestion windows and allow
serviceClass = .interactiveVideoon A against.backgroundon B. On a direct link a second handshake is negligible.
Corrected again by Phase 2: it is three connections, and the spec has not caught up
Preview does not ride as datagrams beside the control stream on A.
NWConnectionGroup+NWMultiplexGroupdid not work, so the code opens a thirdNWConnectionto a secondNWListeneron its own port. The §4.1 claim is satisfied better than described — preview is isolated from stills rather than sharing a window with control — but the durable spec still records the architecture that was planned, not the one that shipped, and that spec is what the H.264 planner will open..interactiveVideois set; nothing sets.backgroundanywhere.And one layer below the split:
NetworkTransport.queueis a single serialDispatchQueueboth connections start on, worth ~40% of the measured interference under saturation. Deliberately not fixed — The architectural claim was measured, and it holds — with a caveat one layer down.
The consequence worth stating plainly: video can be ProRes, 4K60 or 10-bit HLG regardless of what the wireless link can sustain, because the link only carries it after the fact. Camo structurally cannot do this.
Framing is metadata, never pixels — REVERSED 2026-08-26, see below
This section describes the design that was intended, not the one that shipped
Framing shipped destructive: the crop is applied to the saved still and the uncropped original is never written to disk at all. The owner chose this deliberately and reaffirmed it when the contradiction was found. Reasoning and cost are in The reversal of “framing is metadata”.
The original intent below is kept because the arguments for it are still good, and because auto-framing (Phase 6’s remaining half) may want it back.
All framing — manual crop, zoom, pan, aspect ratio, mirror, rotate, level, and auto-framing — was to be stored as a transform alongside the asset. The full-resolution 48MP original is never modified.
Auto-framing (the Center Stage equivalent) is therefore a subject-tracking function that writes the crop rect, not a filter that consumes the frame. This is also how Aposemati escapes Camo’s exclusion matrix.
Prior art: Photo Booth already works this way — non-destructive effects plus File > Export Original…. See 2. Photo Booth is NOT low-res any more.
Pipeline overview
flowchart LR subgraph P["iPhone — Aposemati Camera"] C["AVCaptureSession<br/>48MP sensor"] --> R["On-device recorder<br/><i>full quality</i>"] C --> E["VideoToolbox<br/>low-latency HEVC"] end E -->|"preview<br/>QUIC datagrams"| M R -.->|"file transfer<br/>after the fact"| M M2["shutter / focus / framing"] -->|"control<br/>QUIC stream"| C subgraph MAC["Mac — Aposemati"] M["AVSampleBufferDisplayLayer<br/>viewfinder"] M2["Controls"] M --> L["Library + gallery"] L -.->|"phase 7"| V["CMIO camera extension"] end style R fill:#264653,stroke:#2a9d8f,color:#fff style V fill:#2d2d2d,stroke:#888,color:#fff
Modules
| Module | Platform | Contents |
|---|---|---|
AposematiCore | Shared Swift package, no platform code | Wire protocol, message types, Transport protocol + backends, capture settings model, asset metadata incl. framing transform |
Aposemati Camera | iOS / iPadOS | AVCaptureSession, preview encoder, still capture, on-device recorder, transport publisher |
Aposemati | macOS | Transport browser, preview renderer, controls, library; later hosts the camera system extension |
Hard platform boundaries that cannot be shared: the system extension (macOS only), AVCaptureMultiCamSession (iOS only), Apple Log and HDR colour spaces (iOS only), AVCaptureDeviceTypeDeskViewCamera (macOS only), preview view hosting, and all entitlements.
There is no SwiftUI camera view
Zero camera/capture/video/player symbols across 675 public structs in the macOS 26.2 SwiftUI interface. Preview means wrapping
AVCaptureVideoPreviewLayeror rendering throughAVSampleBufferDisplayLayer.
Phases
The phases were renumbered during execution
Phase 1 became link + shutter + stills (preview moved out to Phase 2), because the four-channel architecture lets preview be added later without touching the transfer path. The table below is the executed numbering.
| Phase | Deliverable | Status |
|---|---|---|
| 0 | Transport spike — measure throughput at real range | ✅ PASSED on hardware — aposemati-phase0-field-measurements |
| 1 | Link, pairing, control channel, shutter → full-res still in the Mac library | ✅ WORKING — aposemati-phase0-phase1-build |
| 2 | Live preview on the Mac (droppable QUIC datagrams) | ✅ COMPLETE, verified on hardware at 30 fps — aposemati-phase2-live-preview, aposemati-crop-and-framing. ⭐ A permanent-freeze defect was found on hardware and fixed 2026-08-26 — aposemati-loopback-blind-spot |
| 3 | Burst capture | Not started |
| 4 | On-device video recording with background transfer; asset lifecycle | Not started |
| 5 | Manual controls and colour pipeline | Not started |
| 6 | Framing: crop/zoom/pan, aspect ratios, mirror/rotate/level, auto-framing | 🟡 crop/zoom/pan SHIPPED 2026-08-26 (destructive, not metadata) — aposemati-crop-and-framing. Aspect/mirror/rotate/level and auto-framing not started |
| 7 | CMIO virtual camera — live webcam output. Where “mirrors Camo” becomes true | Not started |
Phase 0 was not optional — and it earned its place
Apple published no throughput figure for any candidate transport, and no third-party benchmark existed. Building phases 1–4 on an unmeasured link is precisely how the prior research brief went wrong.
Phase 0 not only passed, it caught two things that would have poisoned everything downstream: a probe that was timing the close handshake rather than the transfer (making every reading land near the pass threshold by coincidence), and the discovery that QUIC does not support TLS-PSK, which moved the pairing model mid-build.
Out of scope
The homelab receiver is dead
telep-mainframe’s AX210 has no antenna attached to its u.FL connector — it cannot be a wireless peer at all, independent of any Linux NAN driver question. See telep-mainframe.
Also out: Windows, Android, Linux clients. Apple only.
Notes in this project
| Note | Covers |
|---|---|
| ⭐ aposemati-phase0-phase1-build | START HERE. The working build: live run, architecture as built, what is unverified, how to build. |
| ⭐ aposemati-phase2-live-preview | Phase 2, complete. Live preview over QUIC datagrams; the loss table and the H.264 gate; the ranked hardware checklist; the two-device protocol whose verdict is still blank. |
| ⭐ aposemati-peer-restart-inference-boundary | Seven rebuilds of one restart detector. Peer data must never move the watermark backwards; the fifth answer was to delete the mechanism. |
| ⭐ aposemati-loopback-blind-spot | Loopback cannot reproduce “a send that succeeds into nothing”. Why 546 tests missed a permanently frozen viewfinder; the missing stateUpdateHandler; hand-run mutation evidence. |
| ⭐ aposemati-whole-branch-review | The final review of all 68 commits: POSIX 57 root cause, the 250 ms listener margin, the C1/C2 mutual exclusivity decision, a ~70%-real test suite. |
| aposemati-crop-and-framing | Phase 6, first half. Crop/zoom/pan shipped destructive, reversing “framing is metadata”; the .photo preset’s hidden 17 fps format; the two hardware defects. |
| aposemati-phase0-field-measurements | 339 / 156 Mbps on awdl0, rtt 37 ms unchanged at range, 0.011% retransmission. |
| aposemati-pairing-security-model | Commit-reveal SAS, the 0.77 s machine-in-the-middle, in-memory identity, UI as security boundary. |
| aposemati-network-framework-gotchas | NWBrowser.Result.interfaces, never filter by interface type, QUIC has no TLS-PSK, .ready proves nothing. |
| swift-uncancellable-continuation-trap | The withCheckedContinuation hang that appeared three times and cost two fix rounds. |
| swift-character-isnumber-digit-trap | Character.isNumber accepts Arabic-Indic digits. Hit three times in one codebase. |
| aposemati-apple-signing-gotchas | WWDR G3 missing → 0 valid identities; device registration; security-scoped bookmarks. |
| aposemati-build-process-lessons | Verify by execution; passing tests are not evidence; mutation testing; trace a symptom to its single throw site; commit as you go. |
| aposemati-build-install-run | Build/install/run commands that work — Aposemati.app ≠ AposematiCamera.app, and xcodebuild and devicectl use different UUIDs for the same phone. |
| aposemati-transport-findings | Wi-Fi Aware is iOS-only. AWDL is alive. Surviving transport candidates. USB bandwidth trap. |
| aposemati-apple-api-measurements | Continuity Camera’s 1920x1440 ceiling, VideoToolbox low-latency numbers, Core Image costs, CMIO extension gotchas, distribution. |
| camo-studio-teardown | Camo Studio 2.8.2 at binary level — pricing, the exclusion matrix, absences, architecture. |
| diy-continuity-camera-clone-research | ⚠️ Superseded. Kept as a record; its Wi-Fi Aware architecture is invalidated. |
Related
- aposemati-phase0-phase1-build — the working Phase 0 + Phase 1 build
- aposemati-phase2-live-preview — the Phase 2 live-preview build and the H.264 gate
- aposemati-peer-restart-inference-boundary — the restart-inference security boundary inside preview
- ⭐ aposemati-loopback-blind-spot — the harness limit that hid a real defect from 546 tests, and the fix
- aposemati-crop-and-framing — Phase 6’s shipped crop/zoom/pan and the two defects hardware found
- aposemati-whole-branch-review — the final whole-branch review and its ranked fixes
- diy-continuity-camera-clone-research — the original brief this project corrects
- aposemati-build-install-run — how to build, install and run it on hardware
- telep-mainframe — homelab box, now out of scope