- docs/PLAN.md: full implementation plan (copied from ~/.claude/plans/) - docs/HANDOFF.md: machine-portable status, resume steps, architectural notes, phase status, open decisions Lets the repo stand alone for a fresh checkout on another computer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.4 KiB
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
# 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 intomainand merge.- Current branch in progress:
phase-1-vnc-wiring(branched frommain@ 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.
Critical architectural notes
-
RoyalVNCKit owns its own networking. It constructs its own
NWConnectioninternally fromVNCConnection.Settings. OurTransportprotocol inVNCCoreis not on the RFB path — it's kept as the extension point for future SSH tunneling. Don't try to pipe bytes fromDirectTransportintoVNCConnection. -
Delegate model.
SessionControllershould conform toVNCConnectionDelegateand bridge delegate callbacks (which arrive on internal RoyalVNCKit queues) to@MainActorstate. Password supplied viacredentialFor:completion:callback. -
iOS framebuffer rendering is on us. RoyalVNCKit ships macOS-only
VNCFramebufferView(NSView). We render by grabbingframebuffer.cgImageand settingFramebufferUIView.contentLayer.contentson eachdidUpdateFramebuffercallback. IOSurface-backed path available for zero-copy later. -
Swift 6 strict concurrency is on. Cross-actor hops need care. Use
@MainActoron everything UI-adjacent; mark Transport-style types as actors. -
Name "Screens" is owned by Edovia. Pick a different App Store title before any public artifact.
Dependencies
| Package | Purpose | Version | License |
|---|---|---|---|
| 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 withxcodegen generate.Packages/*/.build/— git-ignored.swift buildor 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 planProject.yml— xcodegen project definitionScreens/App/AppStateController.swift— app-level state machinePackages/VNCCore/Sources/VNCCore/Session/SessionController.swift— the stub that Phase 1 will replace with a realVNCConnectionDelegateintegrationPackages/VNCUI/Sources/VNCUI/Session/FramebufferUIView.swift— where incoming framebufferCGImages land
Open decisions
- App Store name — not "Screens" (trademarked).
- Bundle identifier — currently
com.example.screensplaceholder; 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,NSPrivacyAccessedAPICategoryFileTimestampreasons.