# 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-<topic>` — 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.
