# Handoff — Screens VNC app A snapshot of project state so another machine (or another Claude Code session) can pick up without any out-of-band context. ## Resume on a new machine ```sh # 1. Clone git clone git@gitea.treytartt.com:admin/Screens.git cd Screens # 2. Prerequisites (macOS host) brew install xcodegen # reproducible .xcodeproj generation # Xcode 16+ required (Xcode 26 tested) # 3. Generate the Xcode project (not committed) xcodegen generate # 4. Open in Xcode (or build from CLI) open Screens.xcodeproj # - or - xcodebuild -scheme Screens -destination 'platform=iOS Simulator,name=iPhone 17' build # 5. Fast unit tests (no simulator) cd Packages/VNCCore && swift test # ~0.4s, 3 tests cd ../VNCUI && swift test # ~3s, 1 test ``` ## Git layout - `main` — cumulative integrated history. Default branch. - `phase-N-` — per-phase branches; open a PR into `main` and merge. - Current branch in progress: **`phase-1-vnc-wiring`** (branched from `main` @ Phase 0 scaffold). ## Phase status | Phase | Scope | Status | |-------|-------|--------| | 0 — Scaffold | Packages, app target, xcodegen, RoyalVNCKit dep, CI-compilable | ✅ merged to `main` (commit `2cff17f`) | | 1 — MVP connect/view/tap | Wire `VNCConnectionDelegate`, render framebuffer, touch input, Keychain auth | 🔄 in progress on `phase-1-vnc-wiring` | | 2 — Input parity | Trackpad mode, hardware keyboard, pointer, adaptive quality, reconnect | ⏳ not started | | 3 — Productivity | Clipboard sync, multi-monitor, Apple Pencil, screenshots, view-only, curtain mode | ⏳ not started | | 4 — Polish & ship | iPad multi-window, CloudKit sync, a11y, privacy manifest, TestFlight prep | ⏳ not started | Full plan: [docs/PLAN.md](./PLAN.md). ## Critical architectural notes 1. **RoyalVNCKit owns its own networking.** It constructs its own `NWConnection` internally from `VNCConnection.Settings`. Our `Transport` protocol in `VNCCore` is *not* on the RFB path — it's kept as the extension point for future SSH tunneling. Don't try to pipe bytes from `DirectTransport` into `VNCConnection`. 2. **Delegate model.** `SessionController` should conform to `VNCConnectionDelegate` and bridge delegate callbacks (which arrive on internal RoyalVNCKit queues) to `@MainActor` state. Password supplied via `credentialFor:completion:` callback. 3. **iOS framebuffer rendering is on us.** RoyalVNCKit ships macOS-only `VNCFramebufferView` (NSView). We render by grabbing `framebuffer.cgImage` and setting `FramebufferUIView.contentLayer.contents` on each `didUpdateFramebuffer` callback. IOSurface-backed path available for zero-copy later. 4. **Swift 6 strict concurrency is on.** Cross-actor hops need care. Use `@MainActor` on everything UI-adjacent; mark Transport-style types as actors. 5. **Name "Screens" is owned by Edovia.** Pick a different App Store title before any public artifact. ## Dependencies | Package | Purpose | Version | License | |---------|---------|---------|---------| | [royalvnc](https://github.com/royalapplications/royalvnc) | RFB protocol, encodings, auth | `branch: main` (tagged releases blocked by transitive CryptoSwift unstable-version constraint) | MIT | | Apple first-party | Network, SwiftData, Security, UIKit, SwiftUI, Observation | iOS 18 SDK | — | ## Build artifacts - `Screens.xcodeproj/` — **git-ignored**. Regenerate with `xcodegen generate`. - `Packages/*/.build/` — git-ignored. `swift build` or Xcode resolves. - `Packages/*/Package.resolved` — git-ignored; change if you want reproducible dep versions across machines (recommended for an app target — consider flipping later). ## Files to look at first - `docs/PLAN.md` — full plan - `Project.yml` — xcodegen project definition - `Screens/App/AppStateController.swift` — app-level state machine - `Packages/VNCCore/Sources/VNCCore/Session/SessionController.swift` — the stub that Phase 1 will replace with a real `VNCConnectionDelegate` integration - `Packages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift` — where incoming framebuffer `CGImage`s land ## Open decisions - **App Store name** — not "Screens" (trademarked). - **Bundle identifier** — currently `com.example.screens` placeholder; set to your real prefix. - **Team ID / signing** — currently `CODE_SIGN_STYLE: Automatic`; point at your team for device builds. - **Privacy manifest** — scheduled for Phase 4; will enumerate `UIPasteboard`, `UserDefaults`, `NSPrivacyAccessedAPICategoryFileTimestamp` reasons.