3babe2b3ab
New multiplatform SwiftUI app under apps/zacus-hub/ generated via
XcodeGen (project.yml). Three modes share a HubSession actor that
talks to tools/zacus-gateway over Tailscale-only HTTP/WS.
Game-master: live state stream (WebSocket /v1/state/ws), backend
health badges, hint trigger, journal.
Companion: push-to-talk via AVAudioRecorder (M4A AAC 16 kHz),
fallback file picker, hint request, transcript via voice-bridge
proxy.
Studio: YAML editor with validate/save (existing /v1/studio
routes), plus a Scratch tab hosting a Blockly + zelos-renderer
workspace in WKWebView. 38 custom Zacus block types across 10
categories (Scènes, NPC, Audio, LCD, Hardware ESP32, ESP-NOW,
BOX-3, M5, PLIP, Logique), .sb3 export/import via JSZip (procedure
calls + embedded YAML for lossless round-trip), Flasher sheet that
calls /v1/flash/{board} with auto/hot/cold strategies and shows
per-board step results including the cold-flash idf.py command.
ATS exception domains cover the Tailscale CGNAT range plus the
electron-server / studio / macm1 hostnames so the WebView and
URLSession can hit plain HTTP on the tailnet without TLS.
Token stays in the Keychain (cc.saillant.zacus.hub) — never
committed to source.
2.3 KiB
2.3 KiB
Zacus Hub — SwiftUI app (macOS + iOS)
Foundation scaffolded 2026-05-24. Three modes: Game-master, Companion, Studio.
See docs/specs/2026-05-24-zacus-hub-app.md.
Generate the Xcode project
brew install xcodegen # one-time
cd apps/zacus-hub
xcodegen generate
open ZacusHub.xcodeproj
XcodeGen reads project.yml and produces a multiplatform .xcodeproj
targeting iOS 17 + macOS 14. ZacusHub.xcodeproj/ is git-ignored —
regenerate after editing project.yml or adding source files in new
directories.
Layout
apps/zacus-hub/
├── project.yml XcodeGen spec
├── Resources/
│ ├── Info.plist shared (iOS leaves macOS keys harmless)
│ └── ZacusHub.entitlements sandbox + network + mic + camera
└── Sources/
├── App/ @main, RootView (tabs/sidebar), Settings
├── Shared/ HubSession, HubAPI (actor), Keychain
├── GameMaster/ operator view (sprint 1+)
├── Companion/ player voice + hints (sprint 3+)
└── Studio/ YAML browser (sprint 5+)
All sources live in one app target — Swift sees them as a single module,
so SourceKit errors before xcodegen generate are expected noise.
Configure at first launch
- Start the gateway (
tools/zacus-gateway/README.md), copy the token. - In the app: gear icon → paste URL (e.g.
http://studio:8400) + token. Saved to Keychain (cc.saillant.zacus.hub). - The Settings sheet shows live auth state (
/v1/auth/ping).
Sprint 0 status
| Surface | State |
|---|---|
| App skeleton (3 modes, settings, auth check) | ✅ scaffolded |
| Gateway connection | ✅ wired |
| Game-master state refresh | ✅ pull (stub data) |
| Companion hint request | ✅ wired to gateway proxy |
| Studio scenario browse | ✅ list + read |
| Push-to-talk, live WS, scenario edit | ⏳ later sprints |
Conventions
- Swift 5.10, strict concurrency on.
- All network calls go through
HubAPIactor — never raw URLSession in views. - View files own no network state — they read from
HubSessionor pass via@Stateafter awaiting an actor call. - French for user-visible strings, English for code/comments.