Professional IRL streaming for Android — aiming for full feature parity with Moblin
📲 Install • 📥 Download APK • 📖 User Guide (🇬🇧 EN · 🇫🇷 FR) • 🤖 AI Chat Bot • 🤝 Contribute • 📝 Changelog • 📚 Documentation (DE/EN/FR Handbuch + docs/ai-chat-bot.md + GitHub-Wiki per Doku-Sync synchron) • 🐛 Report Bug • 💬 Discussions
What it is: Vivid is the Android version of Moblin, the open-source IRL streaming app — a professional multi-camera streaming client for Twitch (RTMP/RTMPS) with chat overlay, AI chat bot, widgets, scenes, replays, and manual camera controls, built with Kotlin/Compose and RootEncoder.
Get started:
- 📲 Install: grab the latest APK via the permanent direct download link, from the Releases list, or add the F-Droid repository for automatic updates (APK 24+)
- 📖 User guide: English · Français · Deutsch — plus tutorials, FAQ and troubleshooting
- 🛠 Build from source:
./gradlew assembleFossDebug(Gradle 9.4 wrapper, JDK 25;fossflavor is fully open-source, thestandardflavor adds optional Sentry) - 🤝 Contribute: bugs and features via Issues, code via pull requests to
develop— see CONTRIBUTING.md for the workflow, required checks, and the local pre-push gate; every contribution follows our Code of Conduct - 🔒 Security: please report vulnerabilities privately via SECURITY.md — the project's full security posture (supply-chain hardening, OpenSSF Scorecard context) is documented there; the CII Best Practices checklist maps every badge criterion to its evidence; a Security-Loop guard (
scripts/check_security_loop.sh, part of the pre-push gate + CI + release pipeline) keeps the release-grade security rules (keystore hardening, signature checks, reproducibility, Sentry opt-out proof) structurally present
Vivid is an Android implementation of the open-source Moblin IRL streaming app. The end goal is to be at least functionally equivalent to Moblin — every feature Moblin offers should work in Vivid, adapted to the Android platform.
This README tracks that progress honestly: the Features section marks what is already implemented, what is in progress, and what is still planned. The Parity Status table gives the per-feature status at a glance — the detailed work list lives in PARITY.md.
⚠️ Note: Features marked as planned are not shipped yet — don't rely on them for production streaming until they land.
Vivid is not on Google Play (yet) — APKs are published as GitHub Releases. Everything below is free and takes about 2 minutes.
📄 One-page quickstart: Installation Infographic (SVG)
| Channel | What you get | Best for |
|---|---|---|
🚀 Latest / Stable (v* tags) |
Tested releases with auto-generated release notes | Daily use |
| 🌙 Nightly (prerelease) | Fresh build of every new feature, updated daily | Testers, early adopters |
🧪 Alpha (v*-alpha) |
First stage of versioned releases | Previewing upcoming features |
📄 The full versioning strategy (versionName/versionCode, stage criteria) is documented in RELEASE.md. The complete release history (stable, alpha, nightly — automatically mirrored from GitHub Releases) lives in CHANGELOG.md. How builds get published — cadence, checksums, F-Droid repositories — is documented in docs/distribution.md.
Direct download: the latest stable APK is always available at the permanent link releases/latest/download/app-standard-release.apk — GitHub resolves this permalink to the newest stable release automatically. Alternatively via the releases list:
- Open the Releases page
- Click "Latest" (stable), or expand the prerelease list for nightly / alpha builds
- On stable releases download
app-standard-release.apk(theapp-foss-release.apkis the Sentry-free F-Droid variant); ignoremapping.txtandoutput-metadata.json— those are for developers only. Verify downloads withSHA256SUMS.txt(sha256sum -c); stable releases now additionally ship a sigstore/cosign keyless signature (SHA256SUMS.txt.bundle— bundle with signature, certificate and transparency-log entry) that authenticates the checksum file itself — see docs/distribution.md - If your browser warns about the file type, confirm "Download anyway"
Android blocks APKs from outside the Play Store by default. On first launch of the APK:
- Open the downloaded file in your file manager or notification bar
- Android shows a dialog like "Install unknown apps" → tap Settings
- Allow your browser / file manager to install unknown apps
- Go back and tap Install
🔒 Signing: All official APKs are signed with the same release key. If Android ever shows "App not installed", you may have a corrupted download — delete the file and download it again.
After installation, Vivid asks for camera and microphone permissions when you tap Go Live (notifications are requested too on Android 13+ — they power the streaming status notification). Then follow the Platform Setup Guides to connect Twitch, YouTube, Kick, or your own server.
🔋 Background streaming: While streaming, a persistent notification ("Vivid is streaming") with a Stop action keeps the stream alive when you leave the app or turn the screen off. The encoder runs independent of the camera preview surface (GL-free pipeline), so the stream also continues if you swipe Vivid away from the recents list or rotate the device — the preview simply reappears when you reopen the app. Tap the notification's Stop button (or the Stop button in the app) to end the stream.
✅ Go-Live Self-Check: Before starting, Vivid validates the configured URL and stream key on the streaming screen and shows clear messages (e.g. "Keine Stream-URL konfiguriert", "Nicht unterstütztes Protokoll", missing stream key). Blocking problems prevent the start; warnings are shown but don't block.
Recommended for Android 14+: Use our official F-Droid repository for automatic updates:
📱 Quick Start with QR Code:
- Install F-Droid (falls nicht vorhanden)
- Open F-Droid → Settings → Repositories
- Tap auf + und fügen Sie hinzu: - URL:
https://thoser666.github.io/Vivid/fdroid/repo- Name: Vivid (schnelle Updates)
- Tap Done und warten Sie auf die Synchronisation
- Install Vivid über das neue Repository
✅ Benefits: Updates erscheinen automatisch, kein manueller Download nötig, zukunftssicher ab Android 14+ (Google schränkt Sideloading ein).
🗄️ Archive: Das Repository enthält zusätzlich ein separates Archiv mit allen älteren Versionen (https://thoser666.github.io/Vivid/fdroid/archive). Der F-Droid-Client erkennt es automatisch — ältere Versionen bleiben für Downgrades und als Fallback installierbar.
📝 Note: Dieses Build enthält Sentry für Crash-Reporting. Für ein vollständig FOSS-Build ohne Telemetrie verwenden Sie das offizielle F-Droid-Repository (wenn verfügbar).
Für Benutzer, die Obtainium bevorzugen:
- Install Obtainium von obtainium.imranr.dev (oder eigenen GitHub Releases)
- Tap + → geben Sie
https://github.com/thoser666/Vividals Quelle ein - Es erkennt automatisch GitHub Releases — wählen Sie Ihren Kanal:
- Nur Stable: Neueste Version verfolgen ("Include pre-releases" deaktiviert)
- Nightly: "Include pre-releases" aktivieren, um jeden Feature-Build zu verfolgen
- Tap Hinzufügen — Obtainium prüft jetzt automatisch auf Updates und installiert sie
Da jedes APK mit demselben Schlüssel signiert ist, werden Updates (einschließlich Nightly → Stable und umgekehrt) nahtlos über die vorherige Version installiert.
🧪 Update-Flow testen
- Install ein älteres Nightly APK von der Releases-Seite (z.B. den vorherigen Build)
- Open Settings — die installierte Version wird unten angezeigt, und ein „⬆ Update verfügbar: …" Badge erscheint automatisch, wenn ein neuerer Build existiert
- Fügen Sie die App in Obtainium wie oben beschrieben hinzu (Include pre-releases für nightly aktiviert)
- (Optional) In Settings → „Über Vivid & Updates" tippen Sie auf „Nach Updates suchen", um den neuesten GitHub-Release zu sehen
- In Obtainium tippen Sie Update — das neuere APK wird über die alte Version installiert (gleicher Signatur-Schlüssel)
- Open erneut Settings — die Versionsnummer hat sich erhöht und das Badge ist verschwunden ✅
Die Überprüfung auf dem Über-Bildschirm folgt denselben Regeln wie in RELEASE.md: Es schlägt nur neuere Versionen vor (nightly → nightly/alpha/beta/stable, nie ein Downgrade).
- 🎛️ OBS WebSocket Control - Control OBS Studio directly from your phone (switch scenes, start/stop recording and streaming, input mute, audio levels (dB), audio sync offset, source snapshot, screen black)
- 🌐 Streaming Pipeline - RootEncoder-based live streaming to your configured RTMP/SRT ingest (Twitch, YouTube, Kick, or your own server)
- 🔗 Multi-Streaming - Send the same stream to two RTMP(S) targets in parallel (primary + optional secondary): add a secondary URL/key in Settings → Stream („Multi-Streaming (optional)“) and both targets start on Go Live. Each target shows its own status on the streaming screen (bereit / verbinde… / sendet live / fehlgeschlagen), and if one target fails it stops on its own while the other keeps streaming — ideal for cross-streaming to Twitch and YouTube at the same time
- 🔒 RTMPS (TLS) - Encrypted ingest via
rtmps://(verified against RootEncoder 2.7.5: native TLS handshake, port 443); enabled per-platform or via the TLS toggle, standard port 1935 is auto-normalized to 443 - ✅ Go-Live Self-Check - Before starting the stream, Vivid validates the configured URL and stream key (missing/invalid URL, unsupported protocol, missing key) and shows clear, actionable German messages directly on the streaming screen — blocking errors prevent starting, warnings (e.g. missing key) are shown but don't block
- 🔍 Focus Lock - Toggle autofocus ⇄ infinity lock on the streaming camera to prevent focus hunting (rain drops, dirt on the windshield) during drive/train streams — Moblin #377; works on the actual RootEncoder camera (not just the preview) and can be set before going live
- 👆 Camera Controls on the Streaming Preview - Tap-to-focus (single tap), pinch to zoom (clamped to the camera's zoom range) and zoom reset (double tap) directly on the live preview — gestures drive the real RootEncoder camera, not the preview only. Plus a stabilization toggle (optical stabilization preferred, EIS fallback) and a torch/flashlight toggle (RootEncoder lantern API, also available as
!torchowner bot command) next to the focus-lock button - 🎨 Video Effects - 11 OpenGL filters (Grayscale, Sepia, Noise, Negative, Edge Detection, Cartoon, Pixelated, Blur, Beauty, Duotone + No Filter) via RootEncoder's
setFilter/GlFilterAPI — effects apply to both the live preview and the encoded stream. A cycle button in the streaming screen switches between filters with the current filter name displayed; the owner can also switch filters from chat with!filter <name>(or!filter/!fxto cycle). Localized in all three app languages (de/en/fr) - 💬 Twitch Chat Integration - Full Twitch chat data layer via EventSub (read) + Helix (send), no IRC —
TwitchChatEventSubReader(WebSocketchannel.chat.message) + HelixPOST /helix/chat/messages; on top of it the chat overlay, the AI chat bot and a full settings screen (see below). Formally ✅ with Twitch scope (Beta-Gate): Kick/YouTube/SOOP + Twitch OAuth browser flow (sending & moderation) = post-beta roadmap - 💬 Twitch Chat Overlay - Show the chat of any Twitch channel over the live preview (read via Twitch EventSub, no IRC). Configure the channel and toggle the overlay in Settings → Chat-Overlay; the latest messages appear bottom-left with each user's Twitch color, Twitch badges (Broadcaster/Moderator/Subscriber, fetched via the Helix Chat-Badges API and rendered as CDN images before the username), inline Twitch emotes (rendered as CDN images via Coil) and event alerts (follows, subscriptions, gift subs, resubs and raids — shown as colored banner lines above the chat, auto-dismissed after a few seconds; the bot token needs
moderator:read:followersfor follows, i.e. the bot must be a moderator, andchannel:read:subscriptionsfor subs/gifts/resubs). A test alert can be triggered locally via thetriggerTestAlertAPI (or the owner command!testalert follow|sub|gift|resub|raid) to verify the overlay before going live. The connection auto-reconnects, and the overlay hides itself as soon as it is disabled in the settings - 📊 Twitch-Kanalsteuerung - Die Streaming-Ansicht zeigt die aktuelle Viewerzahl (automatische Aktualisierung alle 30 Sekunden). Unter Settings → Streaming & OBS → Twitch-Kanalsteuerung lassen sich Titel und Kategorie über Twitch Helix setzen. Dafür werden Kanal, Twitch-App-Client-ID und ein Broadcaster-OAuth-Token mit
channel:manage:broadcastbenötigt; fehlt der Broadcaster-Token, wird abwärtskompatibel der Chat-Bot-Token verwendet. OAuth-Tokens (Access + Refresh) werden nach dem PKCE-Login AES-256/GCM-verschlüsselt im Android Keystore gespeichert und bei einem401automatisch über den Refresh-Token erneuert — der Klartext-Settings-Fallback bleibt für bestehende Installationen erhalten. Kategorien werden vor dem Update über die Twitch-Suche in eine Game-ID aufgelöst; Start-Ads und Hype-Train-Steuerung sind weiterhin offen. - 🤖 AI Chat Bot - A fully automated, in-app chat bot (inspired by cloud services like Stream Chat AI): it connects to your Twitch chat when you go live, answers viewers through an LLM of your choice (any OpenAI-compatible endpoint — OpenAI, Gemini, Groq, DeepSeek, or a local Ollama server) and shuts down cleanly when the stream ends. A mode switch in the settings picks between „Bot (wie Moblin)“ (deterministic
!-commands like!help/!uptime/!tts/!bot, no LLM needed) and „KI autonom“ (the AI decides itself whether and how to reply, including staying silent).!ttstoggles chat text-to-speech (owner-only, reads chat messages aloud on the streamer's device, like Moblin's bot). Media commands (!next/!pause/!play/!prev) control the music player (owner + moderators). Mentions-only mode, a reply cooldown and a per-minute rate limit keep it from spamming; configurable limits protect against spam and LLM cost: a per-viewer cooldown (default 60 s), a per-viewer reply cap per stream, and an hourly reply budget (0 = off for each) — platform-neutral via user id, moderators bypass the per-viewer limits; a quick-start preset bar (Locker/Balanced/Streng/Eigene, the last choice is persisted and restored on app start) fills the three limits in one tap, and a live usage readout (replies this hour vs. budget, per-stream total, top viewers) lets the streamer watch the cost budget in the settings screen. A coexistence mode lets it run side by side with another tool's bot (e.g. Rivulet): other bot logins can be ignored and a command scope (@vividbotmention or a custom prefix like!v!help) prevents double replies and double actions. An owner mode (streamer only) adds exclusive commands —!start/!stop/!diag/!ask/!fix/!torch/!filter— that can start/stop the stream, run a diagnostic with recommendations, query a separate, more powerful owner LLM, toggle the flashlight, and cycle through video effects, only the channel owner (broadcaster badge) and explicitly listed logins (e.g. a second account) can use them, viewers get a hint instead. Auto-connect/auto-shutdown is wired into the streaming foreground service — see docs/ai-chat-bot.md - ⚙️ Persisted Stream Settings - Stream URL/key (incl. optional secondary target for multi-streaming) and OBS connection details are stored and reused across sessions
- 🔄 In-App Update Check - Settings shows the installed version + an „Update verfügbar“ badge; the About screen (Settings → "About Vivid & Updates") adds a manual check against GitHub Releases — ideal for verifying Obtainium updates. Results are cached for 1 hour (DataStore), so opening Settings does not hammer the GitHub API rate limit; the manual check in About always refreshes and shows the release notes of the newest build
- 📋 In-App Logs (Logs & Diagnose) - A Settings category „Logs & Diagnose“ with daily log rotation and a configurable retention period (1–30 days, default 7): each calendar day is stored in its own app-internal log file, older days are pruned automatically (also on app start). Crashes are clearly marked — the default uncaught-exception handler writes them with a red CRASH badge (redacted stacktrace) before handing them to Sentry, and the screen shows day sections (Today/Yesterday/date), an „errors & crashes“ filter and a crash summary („X crashes in the last Y days“) so you can analyze and fix recurring failures. Copy/share/clear works across all retained days. Timber trees are planted in the app (
DebugTreefor Logcat in debug builds + aLogBufferTreering buffer + persistentLogStore), and a redaction filter strips stream keys, RTMP URLs, OAuth/LLM/Twitch tokens and passwords before anything is stored or shown — sensitive data never leaves the device in cleartext. This is the foundation for the open remote „logs“ item of the Web Remote Control (later served token-protected via the LAN server) - 🕹️ Web Remote Control - A small LAN server (port 8080, token-protected) exposes the streaming status via
http://<phone-ip>:8080/statusand allows starting/stopping the stream from any browser in the same network — see Installation - 🔋 Background Streaming (Foreground Service) - The stream keeps running when the app is in the background (home button, screen off) and even if the Activity is destroyed (recents swipe, rotation): a foreground service with a persistent notification (live status + stop action) and a partial wake lock keeps the encoder and camera alive, and the encoder runs on a view-independent GL pipeline (RootEncoder Context-constructor) so it never depends on the camera preview surface
- 🔓 Open Source - Completely free and open source
- 🌍 I18n Support — all UI strings externalized into per-module
strings.xml(German default, full Englishvalues-enand full Frenchvalues-fr— three complete languages), including validator/notification/update-check messages; CI gates enforce externalization andvalues↔values-en↔values-frcompleteness (docs/i18n-plan.md). Bot/!diagtexts are intentionally not localized (streamer language).
- 📡 Multi-Network Bonding (SRTLA) - Combine WiFi and mobile data for rock-solid streams
- 💬 Chat Extensions - Emotes (BTTV/FFZ/7TV) plus chat polish: chat polls are implemented (
!poll/!vote/!pollend), and chat display details (hide/gray out deleted messages, replies,/mestyling, cheered bits, adjustable overlay layout) — Viewer count and setting the Twitch stream title/category are implemented; note: moderation (!ban/!timeout/!delete), chat-bot media player control via MediaSession (Apple Music, Spotify, etc.; adapted from Moblin 33.12.0) and the AI chat bot itself are already implemented (see above) - 🎨 Overlays & Widgets - Follower/donation alerts, custom graphics and branding; text widgets incl. weather, timer/stopwatch, distance, G-force and road/route variables (altitude, GPS and speed are already implemented — see above); implemented widgets include the image widget, QR-code widget, battery indicator (with low-battery chat warning) and grid overlay for positioning; further widget types and speech-to-text subtitles remain planned
- 📹 High-Quality Streaming - Up to 4K resolution at 60fps with H.264/AVC and H.265/HEVC
- 🔒 Extended Protocols - SRTLA, RIST, and WHIP (WebRTC) — RTMPS is already implemented (see below); RTMP-Pull/ingest server mode (community request #407); adaptive bitrate for SRT(LA) + per-connection upload statistics
- 🎬 Scenes & Video Sources - ✅ Basic scenes implemented — save and switch complete stream configurations (video source, widget state, stream target) incl. a time-based auto scene switcher; screen capture ✅ and video player ✅ as additional stream sources (multi-cam) — the full „Screen Capture + Video Player“ bucket is done
- 🎛️ Pro Camera Controls - Manual exposure bias, white balance, ISO and focus; back-camera lens selection (ultra-wide/wide/tele); torch and low-light boost
- 📼 Replays - Record to disk (MP4) while streaming and save/play replays
- 🖥️ Externes Display / Streamer-Browser - Video on an external display (Android Cast / Presentation) and a built-in browser visible only to the streamer (Moblin feature)
- 📱 Landscape & Portrait - Landscape in both orientations (video always gravity-down) and a portrait UI with landscape video (Vivid is currently portrait-only)
- ❤️ BLE Fitness Sensors - Heart-rate belt and cycling power monitor (BLE) shown in the text widget — related to the Oura-ring cloud row
- 🕹️ Remote & Companion Features - Web remote control (incl. talkback mic selection, mic/bitrate/zoom control, logs), game controller support, deep linking
- 📸 Photo Shoot Quick Button - Periodically capture high-resolution clean pictures to the gallery; manual snapshots with optional Discord auto-upload (new in Moblin 33.12.0)
Current stage: Beta — the Beta-Gate is formally reached (17/17 Moblin parity ✅, Twitch chat ✅ with scope, ≥1 widget ✅); current: v0.5.8-beta.1 with F-Droid repo. M1 is functionally complete: Slideshow Widget, Twitch OAuth browser flow (PKCE) and optional Twitch start ads are implemented. OAuth callbacks validate the custom scheme, state and PKCE flow before accepting a code; the app exchanges the authorization code with Twitch over HTTPS using the PKCE verifier. The Roborazzi JVM lane remains intentionally disabled under AGP 9/JDK 25; visual coverage currently runs through the emulator Screengrab lane. Snyk now uses the supported CLI setup instead of the deprecated gradle-jdk17 action, with bounded scans, valid directory exclusions and guarded SARIF upload. Tokens must not be logged or embedded in source. The next focus is production hardening, Hype Train support and multi-platform chat.
| Milestone | Version | Ziel | Features |
|---|---|---|---|
| M1: Core Streaming Enhancement | v0.6.0 | Interaktive Chat- und Overlay-Features | ✅ Abgeschlossen: Slideshow-Widget, Twitch-OAuth-Browser-Flow und optionale Start-Ads |
| M2: Advanced Camera & Video | v0.7.0 | Pro-Kamera-Steuerung + verbesserte Videoqualität | Untertitel (Speech-to-Text), OBS Audio-Levels, 4K/60fps + HEVC, Replays (Record-to-Disk) |
| M3: Multi-Platform & Pro Features | v0.8.0 | Multi-Plattform-Chat + erweiterte Streaming-Features | Multi-Platform Chat (Kick, YouTube, SOOP), Adaptive Bitrate, SRTLA Bonding, Streamer-Browser |
| M4: Polish & Ecosystem | v0.9.0 | UI/UX-Verbesserungen + Integrationen | Landscape/Portrait, VTuber/PNGTuber, Externes Display/Cast, BLE-Sensoren |
Aktueller Stand: 39 ✅ / 2 🚧 / 26 📋 von 67 Features. M1 ist abgeschlossen und ausgeliefert (via v0.5.12-beta): Slideshow-Widget, Twitch-OAuth und optionale Start-Ads sind implementiert.
- 🧪 Beta-Build-Checkliste — Beta-Gate-Bedingungen + Play-Unterlagen + ≥2 manuelle Tester
- ✅ Play-Vorbereitung P0–P2 — Master-Checkliste für den ersten Play-Upload;
scripts/test_play_checklist.shschützt die Pflichtpunkte im Pre-Push-Gate
- 💬 Multi-Plattform-Chat (Kick, YouTube, SOOP) — platform adapters + OAuth login
- 🎨 Color-Spaces + 3D-LUTs — PoC: sRGB/P3/Apple Log + 3D-LUT shader
- 📋 Remaining Moblin-parity features — see PARITY.md for full detail
Release stages & criteria: RELEASE.md.
🟣 Twitch Setup
- Go to Twitch Creator Dashboard
- Navigate to Settings → Stream
- Copy your Stream Key
- In Vivid:
- Server:
rtmp://live.twitch.tv/live/ - Stream Key: [paste your key]
- Server:
- Für die Kanalsteuerung unter Settings → Streaming & OBS → Twitch-Kanalsteuerung zusätzlich die Twitch-App-Client-ID, den Kanalnamen und einen Broadcaster-OAuth-Token mit
channel:manage:broadcasteintragen. Vivid verwendet keinen Client-Secret; Tokens werden als geheime Einstellungen behandelt. - Viewerzahl aktualisieren liest den Live-Status. Mit Titel/Kategorie setzen wird die Kategorie über die Twitch-Suche aufgelöst und anschließend zusammen mit dem Titel aktualisiert.
🔴 YouTube Setup
- Open YouTube Studio
- Click "Go Live" → "Stream"
- Copy the Stream URL and Stream Key
- In Vivid:
- Server: [paste stream URL]
- Stream Key: [paste stream key]
🟢 Kick Setup
- Go to Kick Creator Dashboard
- Navigate to Settings → Stream Settings
- Copy your Stream Key
- In Vivid:
- Server:
rtmp://ingest.kick.com/live/ - Stream Key: [paste your key]
- Server:
⚙️ Owncast / Custom Platform (freie RTMP-URL)
Vivid streams protocol-based (RTMP / RTMPS / SRT) — you are not limited to Twitch, YouTube or Kick. Any platform with a standard ingest works via the free Stream URL field; the platform templates (Twitch/YouTube/Kick) are only convenience presets. Example: Owncast (open-source, self-hosted):
- Install Owncast (e.g. Docker:
docker run -p 8080:8080 -p 1935:1935 ghcr.io/owncast/owncast:latest) and open the web UI - Get the ingest data: Owncast shows its RTMP ingest (
rtmp://<your-server>/live) and Stream Key in the admin/stream page - In Vivid → Settings → Streaming & OBS: tap „Benutzerdefiniert“ (Custom) to clear the URL, then enter those values as Stream URL + Stream Key — the field accepts any RTMP(S)/SRT URL; the TLS toggle stays as you left it
- Go Live — the stream goes directly to your server
⚠️ Chat: Vivid's chat (overlay + AI bot) currently connects only to Twitch — Owncast chat is not read yet. Streaming to Owncast works fully; chat integration for custom platforms is on the post-beta roadmap.
🎛️ OBS Studio Setup (WebSocket-Steuerung)
📄 One-page quickstart: OBS-Setup-Infografik (SVG)
- In OBS aktivieren: Extras → WebSocket-Server-Settings → "Enable WebSocket server" anhaken
- Port & Passwort: Standard-Port
4455behalten, optional ein Passwort setzen (wenn keins gesetzt ist, das Feld in Vivid leer lassen) - IP ermitteln: LAN-IP des OBS-Rechners (Windows:
ipconfig, Mac/Linux:ip addr) — Handy und PC müssen im selben WLAN sein - In Vivid verbinden: OBS-Steuerung → ⚙️ Settings → Host = IP, Port =
4455, Passwort + „Secure connection (wss://)“ passend zum Setup (LAN = ws://, Remote = wss://)
🧪 Probleme beim Verbinden? Siehe die OBS-FAQ-Einträge (Verbindung schlägt fehl, Passwort, ws:// vs. wss://).
📡 SRT Server Setup
- Set up your SRT server or use a service provider
- Get your server IP, port, and stream ID
- In Vivid:
- Protocol: SRT
- Server:
srt://[server-ip]:[port] - Stream ID: [your stream ID]
- Configure latency and encryption as needed
🕹️ Web Remote Control (Stream per Browser steuern)
Vivid startet einen kleinen LAN-Server (Port 8080), über den du den Stream-Status abfragen und den Stream starten/stoppen kannst — praktisch, wenn das Handy als Kamera läuft und du vom Laptop steuern willst:
-
Handy und Laptop ins selbe WLAN bringen
-
Token holen: In Vivid unter Settings → Web-Remote-Control steht dein Remote-Token (wird einmalig erzeugt und gespeichert)
-
IP ermitteln: LAN-IP des Handys (Android: Settings → WLAN → Verbundenes Netz → Details)
-
Status abfragen (ohne Token):
curl http://<handy-ip>:8080/status # → {"status":"IDLE"} | {"status":"STREAMING"} | ...
-
Stream starten/stoppen (mit Token):
curl -X POST http://<handy-ip>:8080/start -H "Authorization: Bearer <dein-token>" curl -X POST http://<handy-ip>:8080/stop -H "Authorization: Bearer <dein-token>"
🔒 Der Server läuft nur, solange die App geöffnet ist, und Aktionen benötigen das Token — im selben WLAN ist die Verbindung unverschlüsselt (wie bei OBS ws://), außerhalb des LAN nicht erreichbar.
ℹ️ Android 17 (API 37): Seit
targetSdk 37verlangt Android die "Access local network" permission (ACCESS_LOCAL_NETWORK) für LAN-Server. Falls/statusnicht erreichbar ist, in Vivid unter Settings → Web-Remote-Control auf "Allow LAN access for remote control" tippen (der Server startet danach automatisch neu).
🔧 "App not installed" when installing
Meistens ist der Download beschädigt oder unvollständig:
- Lösche die heruntergeladene
app-release.apkaus deinem Download-Ordner - Lade sie neu von der Releases-Seite herunter
- Prüfe, dass die Datei ~7 MB groß ist (eine deutlich kleinere Datei ist ein fehlgeschlagener Download)
- Versuche es erneut — wenn der Fehler bleibt, installiere über Obtainium (unten), das die Datei verifiziert herunterlädt
Falls du Vivid von einer älteren Version aktualisierst und der Fehler weiterhin auftritt: Deinstalliere zuerst die alte Version (Achtung: Stream-Settings gehen dabei verloren) und installiere dann neu.
📥 "Unknown source not allowed" / Installations-Button ist grau
Android blockiert APKs außerhalb des Play Stores standardmäßig:
- Beim ersten Installationsversuch erscheint ein Note → tippe auf Settings
- Erlaube dem verwendeten Browser / Dateimanager, unbekannte Apps zu installieren
- Go back and tap Install again
- Falls kein Note erscheint: Settings → Apps → [Browser/Dateimanager] → Unbekannte Apps installieren → erlauben
🎥 „Kein Bild“ / Kamera bleibt schwarz beim Streaming
- Prüfe die Kamera-Berechtigung: Settings → Apps → Vivid → Berechtigungen → Kamera = Erlauben (nicht „Nur während der Nutzung“ kann bei Hintergrund-Streaming Probleme machen)
- Teste die Kamera in einer anderen App (z. B. der Standard-Kamera-App) — wenn sie dort auch schwarz ist, liegt es am Gerät
- Falls du mehrere Kameras hast: Wähle in Vivid die richtige Kamera (Front-/Rückkamera) aus
- Starte den Stream neu (Stop → Go Live)
⚠️ Android schließt die Kamera, wenn eine andere App sie belegt (z. B. eine offene Kamera-App oder ein Video-Call). Schließe solche Apps vor dem Streamen.
📶 Verbindungsabbrüche / Stream bricht regelmäßig ab
- Signal prüfen: Mobiles Internet + WiFi — wechsle notfalls den Netzwerktyp und teste erneut
- Ingest-Server wechseln: Wähle in Vivid einen anderen RTMP/SRT-Server deiner Plattform (z. B. einen näher gelegenen)
- Stream-Key prüfen: Ein falscher oder abgelaufener Stream-Key führt zum Abbruch nach wenigen Sekunden — neu kopieren (auf Twitch wird der Key bei jedem Zurücksetzen ungültig)
- OBS-Steuerung deaktivieren: Wenn du OBS nicht benutzt, entferne die OBS-Verbindungsdaten in den Settings — eine fehlgeschlagene OBS-Verbindung kann den Stream-Start blockieren
- Latenz erhöhen: Bei SRT kann eine höhere Latenz (200–500 ms) instabile Verbindungen glätten
📡 Tipp für unterwegs: Ein stabilerer Upload als der nötige ist wichtiger als die maximale Auflösung — senke Qualität/Auflösung bei schwachem Signal, statt den Stream abreißen zu lassen.
🔑 Stream startet, aber Plattform zeigt „Kein Signal“ / Fehler im Dashboard
- Prüfe, ob Server-URL und Stream-Key in Vivid exakt den Werten aus dem Plattform-Dashboard entsprechen (kein Leerzeichen, keine zusätzlichen Zeichen)
- Vergleiche mit den Platform Setup Guides oben
- Twitch: Der Server ist
rtmp://live.twitch.tv/live/— den Key nie mit dem Server verwechseln - Teste den Key zuerst im Plattform-Dashboard („Test stream“), bevor du Vivid startest
🎛️ OBS-Steuerung: Verbindung schlägt fehl
Vivid kann OBS Studio nur steuern, wenn der WebSocket-Server in OBS aktiv und Vivid im selben Netzwerk erreichbar ist:
- WebSocket-Server aktivieren: In OBS unter Extras → WebSocket-Server-Settings → Haken bei "Enable WebSocket server" setzen. Erst dann lauscht OBS auf Verbindungen.
- Host prüfen: In Vivid die IP-Adresse des OBS-Rechners eintragen (z. B.
192.168.1.50) —localhostfunktioniert nur, wenn OBS auf demselben Gerät läuft. IP unter Windows mitipconfig, unter macOS/Linux mitip addrherausfinden. - Port prüfen: Standard ist 4455 — in OBS (WebSocket-Server-Settings) nachsehen, ob ein anderer Port konfiguriert ist, und denselben in Vivid eintragen.
- Gleiches Netzwerk: Handy und OBS-Rechner müssen im selben WLAN/LAN sein (bzw. über VPN verbunden) — prüfe, ob z. B. das Handy im Mobilfunknetz hängt.
- Firewall: Die Windows-Firewall muss eingehende Verbindungen auf Port 4455 erlauben (der OBS-Installer legt meist eine Regel an — nach Updates prüfen).
- Passwort & TLS: Stimmen Passwort und die Option „Secure connection (wss://)“ mit den OBS-Settings überein? Siehe die nächsten beiden FAQ-Einträge.
🧪 Schnelltest: Öffne im Browser auf dem Handy
ws://<OBS-IP>:4455— erscheint eine Meldung, dass die Verbindung hergestellt wurde (auch wenn sie danach geschlossen wird), ist OBS erreichbar und das Problem liegt an Passwort/TLS.
🔑 OBS: Passwort vergessen / „Authentifizierung fehlgeschlagen“
OBS zeigt das WebSocket-Passwort nie wieder an — du kannst es nur neu setzen:
- In OBS: Extras → WebSocket-Server-Settings öffnen
- Haken bei „Passwort aktivieren“ setzen (falls noch nicht geschehen) und ein neues Passwort eingeben
- OK klicken — das neue Passwort gilt sofort
- In Vivid unter OBS-Settings das neue Passwort eintragen und erneut verbinden
⚠️ Kein Passwort in OBS gesetzt? Dann lasse das Passwort-Feld in Vivid leer — ein eingegebenes, falsches Passwort führt zum Abbruch der Verbindung. Umgekehrt: Verlangt OBS ein Passwort und Vivid hat keins, bricht die Verbindung ebenfalls ab (Vivid bricht die Verbindung bewusst ab, statt unauthentifiziert weiterzumachen).
Tipp gegen vergessene Passwörter: Verwende einen Passwort-Manager oder ein einheitliches LAN-Passwort — OBS selbst bietet keine „Passwort anzeigen“-Funktion.
🔐 OBS: ws:// oder wss://? (Secure connection)
Die Option „Secure connection (wss://)“ in den OBS-Settings von Vivid muss zum OBS-Setup passen:
| Verbindung | Wann verwenden | OBS-Voraussetzung |
|---|---|---|
| ws:// (Standard, Schalter aus) | OBS im eigenen LAN/WLAN | Keine — OBS liefert standardmäßig Klartext-WebSockets auf Port 4455 |
| wss:// (Schalter an) | OBS remote über das Internet | OBS muss TLS konfiguriert haben (Zertifikat) oder ein TLS-Reverse-Proxy (z. B. Caddy/nginx) davor laufen |
- Standard-OBS-Setup im LAN = ws:// — also den Schalter aus lassen
- Für Remote-Zugriff (z. B. von unterwegs über Port-Forwarding/VPN) wss:// aktivieren — nur wenn OBS tatsächlich TLS anbietet, sonst schlägt die Verbindung fehl
- Zeigt OBS im Log „WebSocket server started on ws://…“ bzw. „wss://…“, siehst du direkt, welches Protokoll aktiv ist
🔒 Sicherheit: Über öffentliches Internet wird immer wss:// empfohlen — unverschlüsseltes ws:// macht das OBS-Passwort (und damit die Steuerung) für jeden im Netz lesbar. Im heimischen WLAN ist ws:// vertretbar.
🔇 Kein Ton beim Streaming (Audio fehlt)
Bild läuft, aber Zuschauer hören nichts? Das sind die häufigsten Ursachen:
- Mikrofon-Berechtigung prüfen: Settings → Apps → Vivid → Berechtigungen → Mikrofon = Erlauben — ohne sie startet der Audio-Encoder nicht (Vivid zeigt „Failed to prepare audio/video“)
- Mikrofon ist belegt: Android gibt das Mikrofon nur an eine App gleichzeitig — schließe andere Apps, die es nutzen (Anrufe, Sprachassistent, andere Streaming-/Aufnahme-Apps), und starte den Stream neu
- Bluetooth trennen: Ist ein BT-Headset/Headset verbunden, nutzt Android dessen Mikrofon — für IRL-Streaming das Bluetooth-Gerät trennen oder in den Bluetooth-Settings aufs Handy-Mikrofon umstellen
- Lautstärke: Prüfe die Media-Lautstärke (nicht nur Klingelton) — bei 0 ist auch das Streaming stumm
- Neu starten: Nach Berechtigungs-/Bluetooth-Änderungen hilft ein kompletter App-Neustart (Stream stoppen → App beenden → neu starten)
🎧 Plattformseitig: Auch im Plattform-Dashboard prüfen, ob der Audiopegel ankommt (z. B. Twitch Stream Manager) — so unterscheidest du ein Handy- von einem Plattform-Problem.
🔄 Updates kommen nicht an (Obtainium)
- Prüfe, ob du in Obtainium Pre-Releases aktiviert hast (für Nightly-Builds) — Stable-Nutzer bekommen nur
v*-Releases - Tippe in Obtainium auf „Aktualisieren“ (manueller Check), um den letzten Stand abzurufen
- Alle offiziellen APKs sind mit demselben Schlüssel signiert — ein Update sollte immer installierbar sein; falls „App not installed“ erscheint, siehe FAQ oben
❓ Obtainium zeigt eine falsche „Neueste Version“ (z. B. ein altes v0.2.x)
Symptom: Obtainium meldet „Installierte Version ist 0.5.3-beta“, aber „Neueste Version ist v0.2.5“ (oder eine andere Version, die es in Vivid nie gab).
Ursache: Vivid veröffentlicht ausschließlich unter vX.Y.Z-alpha/-beta (aktuell v0.5.4-beta), Nightly-Builds als Pre-Release. Eine „v0.2.5“ existiert weder als Release noch als Tag. Die Anzeige stammt dann aus einem veralteten Cache des Obtainium-Eintrags oder der Eintrag zeigt auf eine falsche/alte Quelle.
Lösung:
- In Obtainium den Vivid-Eintrag öffnen → ⋮-Menü → „App-Daten aktualisieren“ (Refresh), danach „Aktualisieren“ tippen
- Bleibt die Anzeige falsch: Eintrag löschen und neu hinzufügen mit exakt
https://github.com/thoser666/Vivid - Pre-Releases-Toggle: Für Beta/Alpha nicht nötig — diese Releases sind auf GitHub als normale Releases markiert (kein Pre-Release-Flag). Nur für Nightly-Builds den Toggle aktivieren
- Gegenprobe in der App: Settings → "About Vivid & Updates" → "Check for updates" zeigt die echte neueste GitHub-Version — weicht Obtainium davon ab, liegt es am Eintrag, nicht an Vivid
| Area | Technology | Version |
|---|---|---|
| Language | Kotlin | 2.2.20 |
| Build | Android Gradle Plugin | 9.3.1 |
| JDK | Eclipse Temurin (LTS) | 25 |
| SDK | minSdk / compile+target | 24 / 37 |
| UI | Jetpack Compose (BOM) | 2025.09.00 |
| DI | Hilt + KSP | 2.59.2 / 2.3.11 |
| Networking | OkHttp / Ktor | 5.3.2 / 3.5.2 |
| Image Loading | Coil | 2.7.0 |
| Camera | RootEncoder (Stream-Pipeline + Vorschau) | 2.7.5 |
| Media | Media3 (ExoPlayer) | 1.9.0 |
| Serialization | kotlinx.serialization | 1.11.0 |
| Code Analysis | Sentry Gradle Plugin | 6.6.0 |
All versions are centrally defined in gradle/libs.versions.toml.
Status: ✅ implemented · 🚧 in progress · 📋 planned
📋 Full per-feature tracking (responsible module + open tasks) lives in PARITY.md.
| Moblin Feature | Vivid | Notes |
|---|---|---|
| OBS WebSocket Control | ✅ | Scenes, recording, stream start/stop |
| OBS Config via QR Code | ✅ | Import obsws:// / obswebsocket connect info (host, port, password) from the OBS QR code |
| Streaming (RTMP / SRT) | ✅ | Configurable URL/key via settings |
| RTMPS (TLS ingest) | ✅ | rtmps:// via RootEncoder 2.7.5, port 443, TLS verified |
| Background Streaming (Foreground Service) | ✅ | Stream continues in background: notification + wake lock, stop action |
| Go-Live Self-Check | ✅ | Validates URL/key before starting, clear error messages |
| Focus Lock (∞) | ✅ | Autofocus ⇄ infinity lock toggle on the streaming camera (Moblin #377) |
| Persisted Stream Settings | ✅ | Stream & OBS config across sessions |
| I18n Support | ✅ | All UI strings externalized (per-module strings.xml, German default + full English values-en + full French values-fr); CI gates: externalization + values↔values-en↔values-fr completeness + hint-content guard — docs/i18n-plan.md |
| H.264/H.265, up to 4K/60fps | 🚧 | Encoder presets (2160p60…480p30) + codec preference (HEVC-first auto fallback) implemented |
| Multi-Network Bonding (SRTLA) | 📋 | SRTLA algorithm to be ported |
| Chat (Twitch) + Emotes + Moderation | ✅ Twitch-Scope | feature-chat — Twitch EventSub reader (channel.chat.message) + Helix send (POST /helix/chat/messages) + chat overlay over the live preview + inline Twitch emotes (CDN rendering via Coil) + moderation done (!ban/!timeout/!delete) + AI chat bot done (IRC removed); third-party emotes (BTTV/FFZ/7TV) partially implemented (API clients + cache + overlay rendering); Kick/YouTube/SOOP + OAuth (sending/moderation) = post-beta roadmap |
| AI Chat Bot (Vivid extra) | ✅ | Fully automatic LLM chat bot: auto-connect on go-live, clean shutdown on stream end; OpenAI-compatible LLM providers; owner mode (!start/!stop/!diag/!ask, streamer-only via broadcaster badge + allow-list, separate owner LLM) |
| UI Color Schemes (Vivid extra) | ✅ | Material-3 palette (seed #3DDC84) replaces the template colors; appearance settings category „Darstellung“: user toggle System/Light/Dark/AMOLED (pure-black surfaces for OLED) + 6 curated accent colors (M3 TonalSpot palettes, Vivid Green stays the default) — applies live, no restart. Typography follows the current Material-3 baseline of the bundled material3 (no template overrides) |
| Chat-Bot Media Player Control | ✅ | Generic media control via MediaSession (Apple Music, Spotify, …); Android adaptation of Moblin 33.12.0 — commands !song/!next/!pause/!play/!prev (needs notification access) |
| Overlays & Widgets | 🚧 | feature-widgets: text/info widget (time, GPS coordinates, speed, altitude) live as overlay — time/date ticker, LocationProvider (LocationManager), settings toggles, permission flow; template variables ({time}, {date}, {speed}, {altitude}, {lat}, {lon}, {road}, {city}, {country} — placenames via Android Geocoder with a TTL+distance cache) via WidgetVariableResolver + widgetTemplate setting; image, QR-code, battery and grid widgets implemented; further widget types and speech-to-text subtitles remain planned (Twitch chat overlay + event alerts already implemented in feature-chat) |
| Audio Tools (levels, muting, talk-back) | 📋 | |
| Extended Protocols (RIST, WHIP) | 📋 | |
| RTMP-Pull / Ingest (Server mode) | 📋 | Community request #407; Moblin offers ingests (RTMP, SRT(LA), RIST, RTSP, WHIP) |
| Web Remote Control | ✅ | LAN server (port 8080) with token auth: status, start/stop |
| Photo Shoot Quick Button | 📋 | Periodic high-res photos to the gallery; new in Moblin 33.12.0 |
| Game Controller Support | 📋 | |
Deep Linking (moblin://) |
📋 | |
| Scenes (basic) + Auto Scene Switcher | ✅ | StreamScene + SceneRepository (persisted, active scene) + SceneController (applies source/widget/stream target) + time-based AutoSceneSwitcher (interval ≥ 5 s); scene bar in the streaming screen (chips, save, delete, auto toggle — de/en/fr) — open: rule-based switcher, settings section, scene/source widget, live source switching while streaming |
| Pro Camera Controls + Lens Selection | 🚧 | Manual focus distance + lens selection (wide/ultra-wide/tele) implemented with UI (Settings screen); exposure/white balance lock pending RootEncoder upgrade |
| Screen Capture + Video Player as source | ✅ | MediaProjection + basic video player as stream source — bucket done: VideoSourceKind/VideoSource/VideoSourceRegistry (S1), RootEncoder MultiDisplay + consent flow + source toggle (S2), RootEncoder MultiFromFile + SAF video picker (S3); all three sources switchable in the streaming screen |
| Record to Disk (MP4) + Replays | ✅ | MP4-Recording parallel zum Stream, Replay-Bibliothek (Liste, Inline-Wiedergabe, Löschen, Teilen), Audio-Konfiguration (ReplayAudioMode ALL/VIDEO_ONLY) + Thumbnail-Vorschauen, Replay als Szenen-Quelle (Dauerschleife, „Als Stream-Quelle verwenden“ in der Bibliothek) (09.09.) |
| Video Effects (Grayscale, Sepia, Noise, …) | ✅ | 11 OpenGL filters via RootEncoder setFilter/GlFilter, cycle button in streaming screen, !filter owner bot command, i18n de/en/fr |
| Torch / Low-Light Boost | ✅ | Torch: RootEncoder lantern API + !torch bot command. Low-Light Boost: software brightness filter (1.5x gain via GLSL) + !boost bot command — works on all video sources |
| External Display (Cast / HDMI-out) | 📋 | Video on an external display via Android Cast/Presentation |
| VTuber / PNGTuber | 📋 | Basic avatar instead of the camera |
| Image / QR / Battery / Grid Widgets | 🚧 | Image, QR code, battery indicator (+ low-battery chat warning) and grid overlay are implemented; additional widget types remain planned |
| Speech-to-Text Subtitles | 📋 | Live subtitles from the mic as overlay |
| Twitch: Viewer Count, Title/Category, Ads | ✅ | feature-chat, feature-settings, feature-streaming |
| Chat Display Details (deleted msgs, replies, /me, bits) | 📋 | Hide/gray out deleted messages, show replies, /me styling, cheered bits, adjustable layout |
| Chat Poll | ✅ | feature-chat |
| Adaptive Bitrate (SRT/SRTLA) + Upload Stats | ✅ | feature-streaming, core |
| Streamer Browser | 📋 | Built-in browser, visible to the streamer only |
| Landscape / Portrait | 📋 | Landscape 0/180 (gravity-down video) + portrait UI with landscape video |
| BLE Fitness Sensors (HR, Cycling Power) | 📋 | Heart-rate belt + cycling power monitor (related to the Oura-ring row) |
| Module | Purpose |
|---|---|
app |
Application entry point, navigation, DI wiring |
core |
Shared utilities and base classes |
domain |
Business logic, models, use cases |
data |
Repositories and data sources |
feature-streaming |
Streaming pipeline (RootEncoder, encoding) |
feature-chat |
Live chat integration |
feature-settings |
App settings |
feature-widgets |
Stream overlays and widgets |
feature-obs-control |
OBS Studio WebSocket control |
Requirements:
- JDK 17 (minimum) — required by Android Gradle Plugin 9.x
- JDK 25 (recommended, LTS) — newest long-term support version, works perfectly with Gradle 9.7.0
# Clone the repository
git clone https://github.com/thoser666/Vivid.git
cd Vivid
# Open in Android Studio
# OR build with Gradle
./gradlew assembleDebug# Unit tests for all modules (320 tests across core, app, feature-*)
./gradlew testDebugUnitTest
# Live check: run the in-app UpdateChecker against the real GitHub releases
# (disabled in the normal test run; CI runs it with GITHUB_TOKEN)
./gradlew :core:testDebugUnitTest --tests "com.vivid.core.update.LiveUpdateCheckTest" -PliveUpdateCheck=true
# Lint & static analysis
./gradlew lintDebugBoth run automatically in CI (.github/workflows/android-ci.yml) on every push and pull request to develop/master.
Release builds use Fastlane (see Gemfile); dependencies are pinned in Gemfile.lock:
# Install the Ruby toolchain and pinned gems (fastlane 2.237.0 and friends)
bundle install
# Run the same lanes as CI
bundle exec fastlane test
bundle exec fastlane build_debug
bundle exec fastlane build_release # requires the signing secrets from CI
# Build the release APK and publish it as a GitHub release
# (requires the gh CLI and GH_TOKEN; tag defaults to the nearest git tag)
bundle exec fastlane release_github
# Create and push an alpha release tag (runs tests, auto-versions)
bundle exec fastlane release_alphaapp/build.gradle.kts reads the default versionName from the VERSION file and derives a fallback versionCode with the same schema as Fastlane (major*1,000,000 + minor*1,000 + patch*10 + stage; 0.5.14 → 5144). The Ruby self-test scripts/test_version_fallback.rb re-implements that schema and runs in the pre-push gate and CI, so the Gradle fallback and fastlane/release_safety.rb can never drift apart. Fastlane remains authoritative for release builds — the Gradle fallback only covers plain ./gradlew builds without Fastlane.
The release-pipeline.yml workflow runs these lanes in CI. Two release paths are automated:
- A scheduled build runs once per day at 06:00 UTC (and the workflow can be triggered manually via
gh workflow run release-pipeline.yml --ref develop) — it builds the signed release APK and publishes it as a rollingnightlyprerelease with a version derived from the git tag + CI run number. The nightly release is replaced on each build, so it always contains the latest feature build; since 21.08.2026 it is built once per day, not on every push (develop pushes only run tests/builds, no new nightly). - Pushing a
v*tag (e.g.git tag v0.2.0 && git push origin v0.2.0) publishes a stable GitHub release with auto-generated notes.
Both release the same signed APK; Obtainium users can track the latest release for stable versions or enable pre-releases to follow the nightly builds. If a lockfile update is needed (e.g. a security bump), run bundle update <gem> and commit the new Gemfile.lock.
📋 Release stages & criteria (nightly → alpha → beta → stable) are documented in RELEASE.md. The PARITY.md tracker determines which stage is active.
We welcome contributions! Join our Discussions to pitch an idea, then fork and submit a Pull Request:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- 📚 Documentation: Check our Wiki for detailed guides
- 🐛 Bug Reports: Found an issue? Report it here
- 🔒 Security: Found a vulnerability? See SECURITY.md for responsible disclosure
- 💬 Discussions: Join our community discussions
- 💡 Feature Requests: Have an idea? Share it with us
- Moblin - The original iOS app that inspired this project
- Erik Moqvist - Creator of the original Moblin
- The entire open-source streaming community
- All contributors and beta testers
This project is licensed under the MIT License - see the LICENSE file for details.
Vivid does not collect, sell, or share your personal data. Crash reports are sent to Sentry only if you enable them in Settings. See PRIVACY.md for the full privacy policy.
If Vivid helps you with your streaming, please consider:
- ⭐ Starring this repository
- 🍴 Forking and contributing
- 📢 Sharing with other streamers
- 💝 Supporting the original Moblin project
Made with ❤️ for the IRL streaming community

