Capability surface
Eight years of "we should rebuild this from scratch" — finally rebuilt. Below is what's on the kiosk PC the moment you double-click the installer.
Cameras
Each event's capture.cameraBrand picks the primary; fallbackBrand is the resilience plan. If both fail, the always-on webcam service synthesizes frames so a session can still start.
Tested on R100. Live view, shutter via EDSDK, file download to the PC. Operator drops the three Canon DLLs into lib/canon/ — never in the repo.
Targets Alpha 7 IV via SDK v1.11. P/Invoke layer documented for first-deploy verification of Cr_Core.dll export names.
Any UVC device. Falls back to synthetic SkiaSharp frames if none is attached — useful for headless dev and demos.
Transient lifetimes so the factory can dispose failed attempts and try the fallback cleanly. Disposed singletons don't fight retries.
Capture modes
Photos go through the SkiaSharp compositor with the event's overlay PNG. Boomerang + GIF tap the camera's live view feed for a rapid burst, then encode via bundled FFmpeg (palette-optimized GIF; split / reverse / concat MP4 with libx264).
Strips or postcards, 3/4/6-up. Operator-authored overlay PNG layers on top.
Forward+reverse MP4, faststart-encoded for instant browser playback.
Two-pass palettegen + paletteuse. 640px wide, ~10fps.
OpenAI gpt-image-1 or Google Gemini 2.5 Flash Image. Provider chosen per preset.
Selection UI
Each Selection screen has its own selectionStyle. Mix and match across screens — ButtonGrid for mode picking, WheelPicker for filters, CoverFlow for premium events.
Existing visual-editor flow. Touch zones placed where the operator wants them; pressed-state PNGs supported.
Horizontal swipeable carousel. Selected center scales to 1.0 with full opacity; off-center to 0.82 + 0.55 opacity. Auto-wraps.
Vertical scrolling list. Full-width tappable rows with descriptions. Built for accessibility / readability from distance.
5 cards visible (±2 wrap). Center: scale 1.0, pink-glow drop shadow. Sides: skewed away. 280ms cubic ease-out per transition. Tap a side to bring it home; tap center to commit.
Trust + privacy
Three independent on-disk streams. Daily-rotated by filename — no rotation job to break. Operators can ship the audit log with the rest of the event records.
14-file daily rolling. SensitiveScrubbingEnricher redacts API keys, Bearer tokens, and emails BEFORE the file sink.
Consent decisions, admin sign-ins, PIN sets, API key updates, retention purges, R2 deletes. Indefinite retention.
Counters only — no PII, no slugs, no paths. Local JSONL by default; remote POST when MOCHIBOOTH_TELEMETRY_URL is set.
Deployment
Tag a release, GitHub Actions builds + packs + creates a GitHub Release with installer + delta packages. The booth's UpdateService polls every 6h, downloads in the background, and never restarts mid-session — new bits apply on the next cold start.