Files
L'électron rare 3babe2b3ab feat(apps): zacus-hub SwiftUI hub (macOS + iOS)
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.
2026-05-24 10:51:26 +02:00

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

  1. Start the gateway (tools/zacus-gateway/README.md), copy the token.
  2. In the app: gear icon → paste URL (e.g. http://studio:8400) + token. Saved to Keychain (cc.saillant.zacus.hub).
  3. 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 HubAPI actor — never raw URLSession in views.
  • View files own no network state — they read from HubSession or pass via @State after awaiting an actor call.
  • French for user-visible strings, English for code/comments.