diff --git a/.gitignore b/.gitignore
index 5d3e303..abe0eab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,36 +24,33 @@ plugin_config/obs-websocket/
# Machine-local generated data
# ============================================================
-# Generated wrapper for telemetry.json — built by telemetry.sh, not edited.
-# (The JSON itself is tracked: it's the hand-edited source for the wrapper.)
-landing/telemetry.js
-
-# Per-session manifest written by loading.sh — ephemeral, not version-controlled.
-loading/loading.json
-loading/loading.js
-
-# Playlist manifest — generated from the audio in /playlist/, machine-local.
-loading/playlist.json
-loading/playlist.js
-
-# Music daemon command file — written by playlist.sh skip/prev/pause/resume.
-loading/cmd.js
-
-# Audio files for the loading scene (any format). Kept out of git regardless
-# of how they got there (yt-dlp, manual copy, etc.).
-/playlist/
+# Per-session rig data written by `php artisan rig:loading`, `rig:playlist`,
+# `rig:telemetry`. Re-derived on demand from the live system + Twitch API.
+webapp/storage/data/*.json
# OBS WebSocket connection details (port + password) — auto-generated by
-# setup.sh from your existing plugin_config/obs-websocket/config.json.
-vendor/obs-config.js
+# `php artisan rig:setup` from plugin_config/obs-websocket/config.json.
+webapp/public/js/obs-config.js
# Album-art cache written by bridges/mpd-state.py on every track change —
-# overlays load it as `
`. Pure runtime state.
+# the music-box/cover overlay loads it through `/cover.jpg?v=`.
bridges/cover.jpg
-# Local backups created during edits — keep out of git noise.
-landing/*.manual
-loading/*.manual
+# Audio files for the loading/music-box scenes (any format). Kept out of git
+# regardless of how they got there (yt-dlp, manual copy, etc.).
+/playlist/
+
+# Local backups created during rig:telemetry review.
+webapp/storage/data/*.manual
+
+# Laravel-native ignores (composer deps, log + cache + session dirs).
+/webapp/vendor/
+/webapp/node_modules/
+/webapp/storage/logs/*.log
+/webapp/storage/framework/cache/data/
+/webapp/storage/framework/sessions/
+/webapp/storage/framework/views/
+/webapp/bootstrap/cache/*.php
# ============================================================
# OBS runtime / generated state — no value in version control
@@ -99,3 +96,4 @@ __pycache__/
*.pyc
*.pyo
temp
+.claude/
diff --git a/basic/scenes/Default_Stream_HUD.json b/basic/scenes/Default_Stream_HUD.json
index c134ca9..adcb693 100644
--- a/basic/scenes/Default_Stream_HUD.json
+++ b/basic/scenes/Default_Stream_HUD.json
@@ -269,7 +269,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "url": "file:///home/jin/.config/obs-studio/landing/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/landing",
"width": 2560,
"height": 1336,
"fps": 30,
@@ -309,7 +310,7 @@
"id": "ffmpeg_source",
"versioned_id": "ffmpeg_source",
"settings": {
- "local_file": "/home/jin/.config/obs-studio/landing/static-hum.wav",
+ "local_file": "/home/jin/.config/obs-studio/webapp/public/audio/static-hum.wav",
"close_when_inactive": false,
"hw_decode": false,
"is_local_file": true,
@@ -350,9 +351,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/loading/index.html",
- "url": "file:///home/jin/.config/obs-studio/loading/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/loading",
"width": 2560,
"height": 1336,
"restart_when_active": true,
@@ -419,8 +419,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/music/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/music-daemon",
"width": 400,
"height": 100,
"shutdown": true,
@@ -456,8 +456,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/game/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/game",
"width": 2560,
"height": 1336,
"fps": 15,
@@ -494,8 +494,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/goodbye/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/goodbye",
"width": 2560,
"height": 1336,
"fps_custom": true,
@@ -536,7 +536,7 @@
"mixers": 255,
"sync": 0,
"flags": 0,
- "volume": 0.20938195288181305,
+ "volume": 0.19247779250144958,
"balance": 0.5,
"enabled": true,
"muted": false,
@@ -567,7 +567,7 @@
"mixers": 255,
"sync": 0,
"flags": 0,
- "volume": 0.0053968820720911026,
+ "volume": 0.01389647088944912,
"balance": 0.5,
"enabled": true,
"muted": false,
@@ -593,8 +593,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/desktop/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/desktop",
"width": 2560,
"height": 1336,
"fps": 15,
@@ -631,8 +631,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/music-box/index.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/music-box",
"width": 2560,
"height": 1336,
"fps": 30,
@@ -670,9 +670,9 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "is_local_file": true,
- "local_file": "/home/jin/.config/obs-studio/music-box/widget.html",
+ "is_local_file": false,
"undo_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18",
+ "url": "http://127.0.0.1:1118/music-box/widget",
"width": 549,
"height": 880,
"fps": 15,
@@ -709,7 +709,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "url": "file:///home/jin/.config/obs-studio/music-box/cover.html"
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/music-box/cover"
},
"mixers": 255,
"sync": 0,
@@ -741,7 +742,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "url": "file:///home/jin/.config/obs-studio/music-box/cover.html?bars=0"
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/music-box/cover?bars=0"
},
"mixers": 255,
"sync": 0,
@@ -773,7 +775,8 @@
"id": "browser_source",
"versioned_id": "browser_source",
"settings": {
- "url": "file:///home/jin/.config/obs-studio/music-box/nc-music-box.html",
+ "is_local_file": false,
+ "url": "http://127.0.0.1:1118/music-box/nc",
"width": 2560,
"height": 1331,
"fps": 15,
@@ -3683,8 +3686,8 @@
"name": "Good Bye"
}
],
- "current_scene": "Good Bye",
- "current_program_scene": "Good Bye",
+ "current_scene": "Music Box",
+ "current_program_scene": "Music Box",
"canvases": [],
"current_transition": "Luma Wipe",
"transition_duration": 1000,
@@ -3716,7 +3719,7 @@
"saved_projectors": [],
"preview_locked": false,
"scaling_enabled": false,
- "scaling_level": -12,
+ "scaling_level": -14,
"scaling_off_x": 0.0,
"scaling_off_y": 0.0,
"modules": {
diff --git a/basic/scenes/Default_Stream_HUD.json.pre-webapp b/basic/scenes/Default_Stream_HUD.json.pre-webapp
new file mode 100644
index 0000000..e0ef678
--- /dev/null
+++ b/basic/scenes/Default_Stream_HUD.json.pre-webapp
@@ -0,0 +1,3757 @@
+{
+ "name": "Default Stream HUD",
+ "DesktopAudioDevice1": {
+ "prev_ver": 536936450,
+ "name": "Desktop Audio",
+ "uuid": "5c879e8d-88e7-41d6-8371-474b9369d8a5",
+ "id": "pulse_output_capture",
+ "versioned_id": "pulse_output_capture",
+ "settings": {
+ "device_id": "alsa_output.pci-0000_2b_00.3.analog-stereo.monitor"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ "AuxAudioDevice1": {
+ "prev_ver": 536936450,
+ "name": "Mic/Aux",
+ "uuid": "fe24bff3-762e-416b-862a-6273326c13d0",
+ "id": "pulse_input_capture",
+ "versioned_id": "pulse_input_capture",
+ "settings": {
+ "device_id": "default"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ "sources": [
+ {
+ "prev_ver": 536936450,
+ "name": "Starting Soon",
+ "uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea",
+ "id": "image_source",
+ "versioned_id": "image_source",
+ "settings": {
+ "file": "/home/jin/HDD/Images/Gifs/stamd.png"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Doomguard Logo",
+ "uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a",
+ "id": "image_source",
+ "versioned_id": "image_source",
+ "settings": {
+ "file": "/home/jin/cloud.jakubzych.com/_img/logos/dgw.png"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "info",
+ "uuid": "cfcf2652-2777-4b92-a53b-54703f23deff",
+ "id": "text_ft2_source",
+ "versioned_id": "text_ft2_source_v2",
+ "settings": {
+ "text": "Helping twitch.tv/eisenhowler setup stream",
+ "font": {
+ "face": "Sansation",
+ "flags": 0,
+ "size": 14,
+ "style": "Regular"
+ }
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Camera",
+ "uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd",
+ "id": "v4l2_input",
+ "versioned_id": "v4l2_input",
+ "settings": {
+ "device_id": "/dev/video0",
+ "Brightness": 0,
+ "Contrast": 35,
+ "Saturation": 64,
+ "Gamma": 99,
+ "Gain": 2,
+ "input": 0,
+ "pixelformat": 1196444237,
+ "resolution": -1
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {},
+ "filters": [
+ {
+ "prev_ver": 536936450,
+ "name": "Crop/Pad",
+ "uuid": "8ea7885e-70c6-4dfd-b5f9-a7581f61b7c2",
+ "id": "crop_filter",
+ "versioned_id": "crop_filter",
+ "settings": {
+ "top": 360,
+ "right": 700
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ }
+ ]
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Screen Capture (PipeWire)",
+ "uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06",
+ "id": "pipewire-screen-capture-source",
+ "versioned_id": "pipewire-screen-capture-source",
+ "settings": {
+ "RestoreToken": "3951c703-09cb-4e8a-9dfd-14b4090da608"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Screen Capture (PipeWire) 2",
+ "uuid": "1e23924b-8260-4246-b7ee-74456fb62e65",
+ "id": "pipewire-screen-capture-source",
+ "versioned_id": "pipewire-screen-capture-source",
+ "settings": {
+ "RestoreToken": "2b7b68cb-b5aa-4da2-b7b7-3c1e54e997e4"
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Landing — Stand By (Browser)",
+ "uuid": "dd513385-f6d8-44da-a459-20acbe620823",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "url": "file:///home/jin/.config/obs-studio/landing/index.html",
+ "width": 2560,
+ "height": 1336,
+ "fps": 30,
+ "fps_custom": true,
+ "shutdown": false,
+ "restart_when_active": false,
+ "webpage_control_level": 1,
+ "reroute_audio": false
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Landing — Static Hum",
+ "uuid": "16cc92de-4b9b-4b1c-b405-8f089991ac86",
+ "id": "ffmpeg_source",
+ "versioned_id": "ffmpeg_source",
+ "settings": {
+ "local_file": "/home/jin/.config/obs-studio/landing/static-hum.wav",
+ "close_when_inactive": false,
+ "hw_decode": false,
+ "is_local_file": true,
+ "looping": true,
+ "clear_on_media_end": false,
+ "restart_on_activate": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.35087639093399048,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "MediaSource.Restart": [],
+ "MediaSource.Play": [],
+ "MediaSource.Pause": [],
+ "MediaSource.Stop": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Loading Project",
+ "uuid": "6642f830-fbae-4020-8292-a9cb7991e6fc",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/loading/index.html",
+ "url": "file:///home/jin/.config/obs-studio/loading/index.html",
+ "width": 2560,
+ "height": 1336,
+ "restart_when_active": true,
+ "reroute_audio": false
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.1156293973326683,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 2,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Audio",
+ "uuid": "fc5dfd34-bc55-4c92-8b5e-ef305afd1d8e",
+ "id": "pulse_input_capture",
+ "versioned_id": "pulse_input_capture",
+ "settings": {
+ "device_id": "alsa_input.usb-Creative_Technology_Ltd_Creative_Live__Cam_Sync_V3_SN0001-02.analog-stereo"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Audio Player",
+ "uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/music/index.html",
+ "width": 400,
+ "height": 100,
+ "shutdown": true,
+ "reroute_audio": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.13031470775604248,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 2,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "HUD",
+ "uuid": "f409a999-358f-488d-98db-c5c6a01d01b9",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/game/index.html",
+ "width": 2560,
+ "height": 1336,
+ "fps": 15,
+ "fps_custom": true,
+ "shutdown": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "GB",
+ "uuid": "38306c90-5bb8-4603-a21c-09383c300097",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/goodbye/index.html",
+ "width": 2560,
+ "height": 1336,
+ "fps_custom": true,
+ "restart_when_active": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "MPD",
+ "uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "id": "pulse_output_capture",
+ "versioned_id": "pulse_output_capture",
+ "settings": {
+ "device_id": "mpd_stream.monitor"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.19247779250144958,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "MPD Silent",
+ "uuid": "41387cb0-801b-49df-92e6-75c7293bec3f",
+ "id": "pulse_output_capture",
+ "versioned_id": "pulse_output_capture",
+ "settings": {
+ "device_id": "mpd_stream.monitor"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 0.01389647088944912,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Desktop HUD",
+ "uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/desktop/index.html",
+ "width": 2560,
+ "height": 1336,
+ "fps": 15,
+ "fps_custom": true,
+ "shutdown": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Music Box HUD",
+ "uuid": "1b9f5436-864d-4f24-9f92-f45702a23953",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/music-box/index.html",
+ "width": 2560,
+ "height": 1336,
+ "fps": 30,
+ "fps_custom": true,
+ "shutdown": true,
+ "restart_when_active": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Music Box Widget",
+ "uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "is_local_file": true,
+ "local_file": "/home/jin/.config/obs-studio/music-box/widget.html",
+ "undo_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18",
+ "width": 549,
+ "height": 880,
+ "fps": 15,
+ "fps_custom": true,
+ "shutdown": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Cover",
+ "uuid": "54d4ac81-e354-431a-a2dc-a00e5555e8d9",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "url": "file:///home/jin/.config/obs-studio/music-box/cover.html"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Cover Simple",
+ "uuid": "7062784f-7b1b-4728-9067-27128c0d5748",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "url": "file:///home/jin/.config/obs-studio/music-box/cover.html?bars=0"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "NC Music Box HUD",
+ "uuid": "edbd893d-ce53-4c91-bf6c-4d52fbf394d6",
+ "id": "browser_source",
+ "versioned_id": "browser_source",
+ "settings": {
+ "url": "file:///home/jin/.config/obs-studio/music-box/nc-music-box.html",
+ "width": 2560,
+ "height": 1331,
+ "fps": 15,
+ "fps_custom": true
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": [],
+ "ObsBrowser.Refresh": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Waveform Visualizer",
+ "uuid": "f28cc995-6966-4afa-b831-ebb50d89ebe8",
+ "id": "phandasm_waveform_source",
+ "versioned_id": "phandasm_waveform_source",
+ "settings": {
+ "pulse_mode": "peak_magnitude",
+ "audio_source": "MPD",
+ "display_mode": "stepped_bars",
+ "channel_mode": "mono",
+ "render_mode": "solid",
+ "color_base": 4278216704,
+ "step_gap": 3
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Waveform Stereo",
+ "uuid": "bc63aaf3-2ae2-4de9-9c7a-c05e55fa2a11",
+ "id": "phandasm_waveform_source",
+ "versioned_id": "phandasm_waveform_source",
+ "settings": {
+ "audio_source": "MPD",
+ "display_mode": "stepped_bars",
+ "channel_mode": "single",
+ "temporal_smoothing": "exp_moving_avg",
+ "color_base": 4278216704,
+ "bar_width": 28
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {},
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Discord",
+ "uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358",
+ "id": "pulse_output_capture",
+ "versioned_id": "pulse_output_capture",
+ "settings": {
+ "device_id": "discord_stream.monitor"
+ },
+ "mixers": 255,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.mute": [],
+ "libobs.unmute": [],
+ "libobs.push-to-mute": [],
+ "libobs.push-to-talk": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Desktop",
+ "uuid": "af8849dc-ea94-40bf-b018-3297518b1b04",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "custom_size": false,
+ "id_counter": 18,
+ "items": [
+ {
+ "name": "Screen Capture (PipeWire)",
+ "source_uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 13,
+ "group_item_backup": false,
+ "pos": {
+ "x": 534.0,
+ "y": 7.0
+ },
+ "pos_rel": {
+ "x": -1.1167664527893066,
+ "y": -0.98952096700668335
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2017.0,
+ "y": 1213.0
+ },
+ "bounds_rel": {
+ "x": 3.0194611549377441,
+ "y": 1.8158682584762573
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 14,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Desktop HUD",
+ "source_uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 15,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Camera",
+ "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 16,
+ "group_item_backup": false,
+ "pos": {
+ "x": 22.0,
+ "y": 902.0
+ },
+ "pos_rel": {
+ "x": -1.8832335472106934,
+ "y": 0.35029935836791992
+ },
+ "scale": {
+ "x": 0.39754101634025574,
+ "y": 0.39722222089767456
+ },
+ "scale_rel": {
+ "x": 0.32136547565460205,
+ "y": 0.32110777497291565
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Music Box Widget",
+ "source_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 549.0,
+ "y": 880.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 17,
+ "group_item_backup": false,
+ "pos": {
+ "x": 12.0,
+ "y": 6.0
+ },
+ "pos_rel": {
+ "x": -1.8982036113739014,
+ "y": -0.99101793766021729
+ },
+ "scale": {
+ "x": 0.91985428333282471,
+ "y": 0.91931825876235962
+ },
+ "scale_rel": {
+ "x": 0.60589206218719482,
+ "y": 0.60553896427154541
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Discord",
+ "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 18,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [
+ {
+ "control": true,
+ "key": "OBS_KEY_COMMA"
+ }
+ ],
+ "libobs.show_scene_item.13": [],
+ "libobs.hide_scene_item.13": [],
+ "libobs.show_scene_item.14": [],
+ "libobs.hide_scene_item.14": [],
+ "libobs.show_scene_item.15": [],
+ "libobs.hide_scene_item.15": [],
+ "libobs.show_scene_item.16": [],
+ "libobs.hide_scene_item.16": [],
+ "libobs.show_scene_item.17": [],
+ "libobs.hide_scene_item.17": [],
+ "libobs.show_scene_item.18": [],
+ "libobs.hide_scene_item.18": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Game",
+ "uuid": "45b37004-1f57-4395-aeb1-06599415317d",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "custom_size": false,
+ "id_counter": 25,
+ "items": [
+ {
+ "name": "Screen Capture (PipeWire) 2",
+ "source_uuid": "1e23924b-8260-4246-b7ee-74456fb62e65",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 21,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Doomguard Logo",
+ "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 6,
+ "group_item_backup": true,
+ "pos": {
+ "x": 2350.0,
+ "y": -0.99993896484375
+ },
+ "pos_rel": {
+ "x": 1.6017963886260986,
+ "y": -1.0014969110488892
+ },
+ "scale": {
+ "x": 0.35290849208831787,
+ "y": 0.35290849208831787
+ },
+ "scale_rel": {
+ "x": 0.28528529405593872,
+ "y": 0.28528529405593872
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Starting Soon",
+ "source_uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 10,
+ "group_item_backup": true,
+ "pos": {
+ "x": 835.35546875,
+ "y": 488.00006103515625
+ },
+ "pos_rel": {
+ "x": -0.66563552618026733,
+ "y": -0.26946097612380981
+ },
+ "scale": {
+ "x": 2.042553186416626,
+ "y": 2.0388350486755371
+ },
+ "scale_rel": {
+ "x": 1.6511658430099487,
+ "y": 1.6481600999832153
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "Starting Soon Show Transition",
+ "transition": {},
+ "duration": 1000
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "info",
+ "source_uuid": "cfcf2652-2777-4b92-a53b-54703f23deff",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 8,
+ "group_item_backup": true,
+ "pos": {
+ "x": 911.3555908203125,
+ "y": 1192.0
+ },
+ "pos_rel": {
+ "x": -0.55186289548873901,
+ "y": 0.7844310998916626
+ },
+ "scale": {
+ "x": 2.5,
+ "y": 2.5
+ },
+ "scale_rel": {
+ "x": 2.0209579467773438,
+ "y": 2.0209579467773438
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "STAND BY",
+ "source_uuid": "d730eeb6-8969-4265-b033-5f777686ce2d",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 12,
+ "group_item_backup": false,
+ "pos": {
+ "x": 835.35546875,
+ "y": -0.99993896484375
+ },
+ "pos_rel": {
+ "x": -0.66563552618026733,
+ "y": -1.0014969110488892
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {
+ "collapsed": false
+ }
+ },
+ {
+ "name": "Audio Player",
+ "source_uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 22,
+ "group_item_backup": false,
+ "pos": {
+ "x": -315.0,
+ "y": 87.0
+ },
+ "pos_rel": {
+ "x": -2.3877246379852295,
+ "y": -0.86976051330566406
+ },
+ "scale": {
+ "x": 0.5975000262260437,
+ "y": 0.60000002384185791
+ },
+ "scale_rel": {
+ "x": 0.5975000262260437,
+ "y": 0.60000002384185791
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "HUD",
+ "source_uuid": "f409a999-358f-488d-98db-c5c6a01d01b9",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 23,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Camera",
+ "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 16,
+ "group_item_backup": false,
+ "pos": {
+ "x": 83.0,
+ "y": 88.0
+ },
+ "pos_rel": {
+ "x": -1.7919161319732666,
+ "y": -0.86826348304748535
+ },
+ "scale": {
+ "x": 0.24262295663356781,
+ "y": 0.24318182468414307
+ },
+ "scale_rel": {
+ "x": 0.19613233208656311,
+ "y": 0.19658410549163818
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "Camera Show Transition",
+ "transition": {
+ "luma_image": "checkerboard-small.png"
+ },
+ "duration": 1000
+ },
+ "hide_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "Camera Hide Transition",
+ "transition": {
+ "luma_image": "checkerboard-small.png"
+ },
+ "duration": 1000
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 24,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Discord",
+ "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 25,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [
+ {
+ "control": true,
+ "key": "OBS_KEY_PERIOD"
+ }
+ ],
+ "libobs.show_scene_item.21": [],
+ "libobs.hide_scene_item.21": [],
+ "libobs.show_scene_item.12": [],
+ "libobs.hide_scene_item.12": [],
+ "libobs.show_scene_item.22": [],
+ "libobs.hide_scene_item.22": [],
+ "libobs.show_scene_item.23": [],
+ "libobs.hide_scene_item.23": [],
+ "libobs.show_scene_item.16": [],
+ "libobs.hide_scene_item.16": [],
+ "libobs.show_scene_item.24": [],
+ "libobs.hide_scene_item.24": [],
+ "libobs.show_scene_item.25": [],
+ "libobs.hide_scene_item.25": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {
+ "transition": ""
+ }
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Landing",
+ "uuid": "2b56b1b1-2f3e-44f0-ac0f-5d33cad38551",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "id_counter": 6,
+ "custom_size": false,
+ "items": [
+ {
+ "name": "Landing — Stand By (Browser)",
+ "source_uuid": "dd513385-f6d8-44da-a459-20acbe620823",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": 4.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.910179615020752,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "Landing — Stand By (Browser) Hide Transition",
+ "transition": {
+ "luma_image": "cloud.png"
+ },
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Landing — Static Hum",
+ "source_uuid": "16cc92de-4b9b-4b1c-b405-8f089991ac86",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Doomguard Logo",
+ "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 4,
+ "group_item_backup": false,
+ "pos": {
+ "x": 1213.0,
+ "y": 119.0
+ },
+ "pos_rel": {
+ "x": -0.1002994030714035,
+ "y": -0.82185626029968262
+ },
+ "scale": {
+ "x": 0.42642644047737122,
+ "y": 0.42642644047737122
+ },
+ "scale_rel": {
+ "x": 0.42642644047737122,
+ "y": 0.42642644047737122
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD Silent",
+ "source_uuid": "41387cb0-801b-49df-92e6-75c7293bec3f",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 6,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.4": [],
+ "libobs.hide_scene_item.4": [],
+ "libobs.show_scene_item.6": [],
+ "libobs.hide_scene_item.6": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {
+ "transition": ""
+ }
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Project Loading",
+ "uuid": "6b8e29a8-a66b-44f2-856e-bd41fb18720d",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "id_counter": 7,
+ "custom_size": false,
+ "items": [
+ {
+ "name": "Loading Project",
+ "source_uuid": "6642f830-fbae-4020-8292-a9cb7991e6fc",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Audio",
+ "source_uuid": "fc5dfd34-bc55-4c92-8b5e-ef305afd1d8e",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 7,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.7": [],
+ "libobs.hide_scene_item.7": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Good Bye",
+ "uuid": "ff28214d-6519-4b4b-a00a-c68498c606ef",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "id_counter": 3,
+ "custom_size": false,
+ "items": [
+ {
+ "name": "Audio Player",
+ "source_uuid": "b7b89406-53f4-45ba-aa1a-c20d17b1c905",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": -101.0,
+ "y": 173.0
+ },
+ "pos_rel": {
+ "x": -2.0673651695251465,
+ "y": -0.74101793766021729
+ },
+ "scale": {
+ "x": 1.5,
+ "y": 1.5
+ },
+ "scale_rel": {
+ "x": 1.5,
+ "y": 1.5
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "GB",
+ "source_uuid": "38306c90-5bb8-4603-a21c-09383c300097",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 3,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.3": [],
+ "libobs.hide_scene_item.3": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Music Box",
+ "uuid": "747b2411-45a9-471a-b0dc-dfe39b0d6385",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "id_counter": 9,
+ "custom_size": false,
+ "items": [
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Music Box HUD",
+ "source_uuid": "1b9f5436-864d-4f24-9f92-f45702a23953",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Cover Simple",
+ "source_uuid": "7062784f-7b1b-4728-9067-27128c0d5748",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 4,
+ "group_item_backup": false,
+ "pos": {
+ "x": 1711.0,
+ "y": 176.0
+ },
+ "pos_rel": {
+ "x": 0.64520961046218872,
+ "y": -0.7365269660949707
+ },
+ "scale": {
+ "x": 0.36875000596046448,
+ "y": 0.36833333969116211
+ },
+ "scale_rel": {
+ "x": 0.36875000596046448,
+ "y": 0.36833333969116211
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "NC Music Box HUD",
+ "source_uuid": "edbd893d-ce53-4c91-bf6c-4d52fbf394d6",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 5,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "NC Music Box HUD Show Transition",
+ "transition": {
+ "luma_image": "checkerboard-small.png"
+ },
+ "duration": 300
+ },
+ "hide_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "NC Music Box HUD Hide Transition",
+ "transition": {
+ "luma_image": "checkerboard-small.png"
+ },
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Waveform Visualizer",
+ "source_uuid": "f28cc995-6966-4afa-b831-ebb50d89ebe8",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 6,
+ "group_item_backup": false,
+ "pos": {
+ "x": 2166.0,
+ "y": 1078.0
+ },
+ "pos_rel": {
+ "x": 1.3263473510742188,
+ "y": 0.61377251148223877
+ },
+ "scale": {
+ "x": 0.38249999284744263,
+ "y": 0.38222223520278931
+ },
+ "scale_rel": {
+ "x": 0.38249999284744263,
+ "y": 0.38222223520278931
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Discord",
+ "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 7,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [
+ {
+ "control": true,
+ "key": "OBS_KEY_M"
+ }
+ ],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.4": [],
+ "libobs.hide_scene_item.4": [],
+ "libobs.show_scene_item.5": [],
+ "libobs.hide_scene_item.5": [],
+ "libobs.show_scene_item.6": [],
+ "libobs.hide_scene_item.6": [],
+ "libobs.show_scene_item.7": [],
+ "libobs.hide_scene_item.7": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ },
+ {
+ "prev_ver": 536936450,
+ "name": "Desktop (No Cam)",
+ "uuid": "e68f67a3-f90b-4e81-a89b-308a0ea83e57",
+ "id": "scene",
+ "versioned_id": "scene",
+ "settings": {
+ "id_counter": 10,
+ "custom_size": false,
+ "items": [
+ {
+ "name": "Screen Capture (PipeWire)",
+ "source_uuid": "8f6ef725-1eec-4fdf-930a-2aab93d84c06",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 1,
+ "group_item_backup": false,
+ "pos": {
+ "x": 10.0,
+ "y": 10.0
+ },
+ "pos_rel": {
+ "x": -1.9011975526809692,
+ "y": -0.98502993583679199
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2127.0,
+ "y": 1289.0
+ },
+ "bounds_rel": {
+ "x": 3.1841316223144531,
+ "y": 1.9296407699584961
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "MPD",
+ "source_uuid": "25440930-0606-46d9-ba2c-be786ff4a3ae",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 2,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Desktop HUD",
+ "source_uuid": "8acfb832-cfb4-4310-8ebb-b58fad2b3509",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 1,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 3,
+ "group_item_backup": false,
+ "pos": {
+ "x": -1.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.917664647102356,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "bounds_rel": {
+ "x": 3.8323352336883545,
+ "y": 2.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Camera",
+ "source_uuid": "a8b362a1-91a6-491b-8751-26e2dad55ccd",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 4,
+ "group_item_backup": false,
+ "pos": {
+ "x": 2019.0,
+ "y": 22.0
+ },
+ "pos_rel": {
+ "x": 1.1062874794006348,
+ "y": -0.96706587076187134
+ },
+ "scale": {
+ "x": 0.34521940350532532,
+ "y": 0.3454001247882843
+ },
+ "scale_rel": {
+ "x": 0.34521940350532532,
+ "y": 0.3454001247882843
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Music Box Widget",
+ "source_uuid": "f662d513-6fe6-49fd-99f6-ea7f44e8de18",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 5,
+ "group_item_backup": false,
+ "pos": {
+ "x": 2156.0,
+ "y": 597.0
+ },
+ "pos_rel": {
+ "x": 1.3113772869110107,
+ "y": -0.10628741979598999
+ },
+ "scale": {
+ "x": 0.7012750506401062,
+ "y": 0.70113635063171387
+ },
+ "scale_rel": {
+ "x": 0.7012750506401062,
+ "y": 0.70113635063171387
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Cover",
+ "source_uuid": "54d4ac81-e354-431a-a2dc-a00e5555e8d9",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 6,
+ "group_item_backup": false,
+ "pos": {
+ "x": 2158.0,
+ "y": 13.0
+ },
+ "pos_rel": {
+ "x": 1.3143712282180786,
+ "y": -0.98053890466690063
+ },
+ "scale": {
+ "x": 0.48124998807907104,
+ "y": 0.48166665434837341
+ },
+ "scale_rel": {
+ "x": 0.48124998807907104,
+ "y": 0.48166665434837341
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Waveform Stereo",
+ "source_uuid": "bc63aaf3-2ae2-4de9-9c7a-c05e55fa2a11",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 8,
+ "group_item_backup": false,
+ "pos": {
+ "x": 2160.0,
+ "y": 470.0
+ },
+ "pos_rel": {
+ "x": 1.317365288734436,
+ "y": -0.29640716314315796
+ },
+ "scale": {
+ "x": 0.49625000357627869,
+ "y": 0.4977777898311615
+ },
+ "scale_rel": {
+ "x": 0.49625000357627869,
+ "y": 0.4977777898311615
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 300
+ },
+ "hide_transition": {
+ "duration": 300
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Discord",
+ "source_uuid": "0d7d9693-0a0c-4a52-af3a-1ec742590358",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 2560.0,
+ "y": 1336.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 10,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "scale_rel": {
+ "x": 1.0,
+ "y": 1.0
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "OBSBasic.SelectScene": [],
+ "libobs.show_scene_item.1": [],
+ "libobs.hide_scene_item.1": [],
+ "libobs.show_scene_item.2": [],
+ "libobs.hide_scene_item.2": [],
+ "libobs.show_scene_item.3": [],
+ "libobs.hide_scene_item.3": [],
+ "libobs.show_scene_item.4": [],
+ "libobs.hide_scene_item.4": [],
+ "libobs.show_scene_item.5": [],
+ "libobs.hide_scene_item.5": [],
+ "libobs.show_scene_item.6": [],
+ "libobs.hide_scene_item.6": [],
+ "libobs.show_scene_item.8": [],
+ "libobs.hide_scene_item.8": [],
+ "libobs.show_scene_item.10": [],
+ "libobs.hide_scene_item.10": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ }
+ ],
+ "groups": [
+ {
+ "prev_ver": 536936450,
+ "name": "STAND BY",
+ "uuid": "d730eeb6-8969-4265-b033-5f777686ce2d",
+ "id": "group",
+ "versioned_id": "group",
+ "settings": {
+ "custom_size": true,
+ "cx": 1633,
+ "cy": 1233,
+ "id_counter": 0,
+ "items": [
+ {
+ "name": "Doomguard Logo",
+ "source_uuid": "ee77caf1-a490-45fa-80d9-4072f7e63d9a",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 6,
+ "group_item_backup": false,
+ "pos": {
+ "x": 1514.64453125,
+ "y": 0.0
+ },
+ "pos_rel": {
+ "x": 0.35126429796218872,
+ "y": -1.0
+ },
+ "scale": {
+ "x": 0.35290849208831787,
+ "y": 0.35290849208831787
+ },
+ "scale_rel": {
+ "x": 0.28528529405593872,
+ "y": 0.28528529405593872
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "Starting Soon",
+ "source_uuid": "4b902d7f-9205-444c-8c8b-b559479d5bea",
+ "visible": true,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 10,
+ "group_item_backup": false,
+ "pos": {
+ "x": 0.0,
+ "y": 489.0
+ },
+ "pos_rel": {
+ "x": -1.9161676168441772,
+ "y": -0.26796406507492065
+ },
+ "scale": {
+ "x": 2.042553186416626,
+ "y": 2.0388350486755371
+ },
+ "scale_rel": {
+ "x": 1.6511657238006592,
+ "y": 1.6481600999832153
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "id": "wipe_transition",
+ "versioned_id": "wipe_transition",
+ "name": "Starting Soon Show Transition",
+ "transition": {},
+ "duration": 1000
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ },
+ {
+ "name": "info",
+ "source_uuid": "cfcf2652-2777-4b92-a53b-54703f23deff",
+ "visible": false,
+ "locked": false,
+ "rot": 0.0,
+ "scale_ref": {
+ "x": 1920.0,
+ "y": 1080.0
+ },
+ "align": 5,
+ "bounds_type": 0,
+ "bounds_align": 0,
+ "bounds_crop": false,
+ "crop_left": 0,
+ "crop_top": 0,
+ "crop_right": 0,
+ "crop_bottom": 0,
+ "id": 8,
+ "group_item_backup": false,
+ "pos": {
+ "x": 76.0001220703125,
+ "y": 1193.0
+ },
+ "pos_rel": {
+ "x": -1.8023951053619385,
+ "y": 0.78592813014984131
+ },
+ "scale": {
+ "x": 2.5,
+ "y": 2.5
+ },
+ "scale_rel": {
+ "x": 2.0209579467773438,
+ "y": 2.0209579467773438
+ },
+ "bounds": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "bounds_rel": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "scale_filter": "disable",
+ "blend_method": "default",
+ "blend_type": "normal",
+ "show_transition": {
+ "duration": 0
+ },
+ "hide_transition": {
+ "duration": 0
+ },
+ "private_settings": {}
+ }
+ ]
+ },
+ "mixers": 0,
+ "sync": 0,
+ "flags": 0,
+ "volume": 1.0,
+ "balance": 0.5,
+ "enabled": true,
+ "muted": false,
+ "push-to-mute": false,
+ "push-to-mute-delay": 0,
+ "push-to-talk": false,
+ "push-to-talk-delay": 0,
+ "hotkeys": {
+ "libobs.show_scene_item.6": [],
+ "libobs.hide_scene_item.6": [],
+ "libobs.show_scene_item.10": [],
+ "libobs.hide_scene_item.10": [],
+ "libobs.show_scene_item.8": [],
+ "libobs.hide_scene_item.8": []
+ },
+ "deinterlace_mode": 0,
+ "deinterlace_field_order": 0,
+ "monitoring_type": 0,
+ "canvas_uuid": "6c69626f-6273-4c00-9d88-c5136d61696e",
+ "private_settings": {}
+ }
+ ],
+ "scene_order": [
+ {
+ "name": "Landing"
+ },
+ {
+ "name": "Project Loading"
+ },
+ {
+ "name": "Game"
+ },
+ {
+ "name": "Desktop"
+ },
+ {
+ "name": "Desktop (No Cam)"
+ },
+ {
+ "name": "Music Box"
+ },
+ {
+ "name": "Good Bye"
+ }
+ ],
+ "current_scene": "Good Bye",
+ "current_program_scene": "Good Bye",
+ "canvases": [],
+ "current_transition": "Luma Wipe",
+ "transition_duration": 1000,
+ "transitions": [
+ {
+ "name": "Luma Wipe",
+ "id": "wipe_transition",
+ "settings": {
+ "luma_image": "checkerboard-small.png"
+ }
+ }
+ ],
+ "quick_transitions": [
+ {
+ "name": "Cut",
+ "duration": 300,
+ "hotkeys": [],
+ "id": 1,
+ "fade_to_black": false
+ },
+ {
+ "name": "Fade",
+ "duration": 300,
+ "hotkeys": [],
+ "id": 2,
+ "fade_to_black": false
+ }
+ ],
+ "saved_projectors": [],
+ "preview_locked": false,
+ "scaling_enabled": false,
+ "scaling_level": -14,
+ "scaling_off_x": 0.0,
+ "scaling_off_y": 0.0,
+ "modules": {
+ "scripts-tool": [],
+ "output-timer": {
+ "streamTimerHours": 0,
+ "streamTimerMinutes": 0,
+ "streamTimerSeconds": 30,
+ "recordTimerHours": 0,
+ "recordTimerMinutes": 0,
+ "recordTimerSeconds": 30,
+ "autoStartStreamTimer": false,
+ "autoStartRecordTimer": false,
+ "pauseRecordTimer": false
+ },
+ "auto-scene-switcher": {
+ "interval": 300,
+ "non_matching_scene": "Nuclear",
+ "switch_if_not_matching": true,
+ "active": false,
+ "switches": [
+ {
+ "scene": "Game",
+ "window_title": "Heroes of Might and Magic III: Horn of the Abyss"
+ }
+ ]
+ }
+ },
+ "resolution": {
+ "x": 2560,
+ "y": 1336
+ },
+ "migration_resolution": {
+ "x": 1920,
+ "y": 1080
+ },
+ "version": 2
+}
\ No newline at end of file
diff --git a/scripts/obs-webapp.supervisord.conf b/scripts/obs-webapp.supervisord.conf
new file mode 100644
index 0000000..cbdaa4d
--- /dev/null
+++ b/scripts/obs-webapp.supervisord.conf
@@ -0,0 +1,31 @@
+; supervisord program file for the OPHI-118 scene overlay webapp.
+;
+; Listens on 127.0.0.1:1118 (CH 118.0 in the overlay lore, easy to remember).
+;
+; Install:
+; sudo install -m 644 scripts/obs-webapp.supervisord.conf /etc/supervisor.d/obs-webapp.conf
+; sudo supervisorctl reread && sudo supervisorctl update
+;
+; Restart after config / route / env changes:
+; sudo supervisorctl restart obs-webapp
+;
+; Logs:
+; tail -F webapp/storage/logs/supervisord.{out,err}.log
+
+[program:obs-webapp]
+command=/usr/bin/php artisan serve --host=127.0.0.1 --port=1118
+directory=/home/jin/.config/obs-studio/webapp
+user=jin
+environment=HOME="/home/jin",USER="jin",PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
+autostart=true
+autorestart=true
+startsecs=2
+startretries=3
+stopwaitsecs=10
+stopsignal=TERM
+stdout_logfile=/home/jin/.config/obs-studio/webapp/storage/logs/supervisord.out.log
+stderr_logfile=/home/jin/.config/obs-studio/webapp/storage/logs/supervisord.err.log
+stdout_logfile_maxbytes=10MB
+stdout_logfile_backups=3
+stderr_logfile_maxbytes=10MB
+stderr_logfile_backups=3
diff --git a/scripts/rewrite-scene-urls.py b/scripts/rewrite-scene-urls.py
new file mode 100755
index 0000000..0215ee9
--- /dev/null
+++ b/scripts/rewrite-scene-urls.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+"""Rewrite OBS browser_source URLs in a scene-collection JSON from `file://` to
+`http://127.0.0.1:1118/`.
+
+Usage:
+ python3 scripts/rewrite-scene-urls.py basic/scenes/Default_Stream_HUD.json
+
+Idempotent: runs against a partially-converted file are no-ops.
+
+Also moves the landing/static-hum.wav ffmpeg_source path to its new home under
+webapp/public/audio/.
+
+OBS MUST be closed when this runs — OBS rewrites scene files on exit.
+"""
+import json
+import re
+import sys
+
+
+BROWSER_MAPPING = {
+ 'landing/index.html': 'http://127.0.0.1:1118/landing',
+ 'loading/index.html': 'http://127.0.0.1:1118/loading',
+ 'game/index.html': 'http://127.0.0.1:1118/game',
+ 'desktop/index.html': 'http://127.0.0.1:1118/desktop',
+ 'goodbye/index.html': 'http://127.0.0.1:1118/goodbye',
+ 'music/index.html': 'http://127.0.0.1:1118/music-daemon',
+ 'music-box/index.html': 'http://127.0.0.1:1118/music-box',
+ 'music-box/widget.html': 'http://127.0.0.1:1118/music-box/widget',
+ 'music-box/cover.html': 'http://127.0.0.1:1118/music-box/cover',
+ 'music-box/nc-music-box.html': 'http://127.0.0.1:1118/music-box/nc',
+}
+
+AUDIO_OLD = 'landing/static-hum.wav'
+AUDIO_NEW = 'webapp/public/audio/static-hum.wav'
+
+
+def rewrite_browser_source(src):
+ s = src.get('settings', {})
+ for old, new in BROWSER_MAPPING.items():
+ for k in ('url', 'local_file'):
+ v = s.get(k, '')
+ if old in v:
+ # Preserve query strings (e.g. ?bars=0).
+ m = re.search(r'\?[^"\s]*$', v)
+ qs = m.group(0) if m else ''
+ s['url'] = new + qs
+ s.pop('local_file', None)
+ s['is_local_file'] = False
+ return True
+ return False
+
+
+def rewrite_audio_source(src):
+ s = src.get('settings', {})
+ lf = s.get('local_file', '')
+ if lf.endswith(AUDIO_OLD):
+ s['local_file'] = lf.replace(AUDIO_OLD, AUDIO_NEW)
+ return True
+ return False
+
+
+def main():
+ if len(sys.argv) != 2:
+ print(__doc__, file=sys.stderr)
+ return 2
+ path = sys.argv[1]
+ doc = json.load(open(path))
+ rewrites = 0
+ for src in doc.get('sources', []):
+ sid = src.get('id', '')
+ if sid == 'browser_source':
+ if rewrite_browser_source(src):
+ rewrites += 1
+ elif sid == 'ffmpeg_source':
+ if rewrite_audio_source(src):
+ rewrites += 1
+ json.dump(doc, open(path, 'w'), indent=4, ensure_ascii=False)
+ print(f'wrote {path} ({rewrites} sources rewritten)')
+
+
+if __name__ == '__main__':
+ sys.exit(main() or 0)
diff --git a/webapp/.editorconfig b/webapp/.editorconfig
new file mode 100644
index 0000000..6df8428
--- /dev/null
+++ b/webapp/.editorconfig
@@ -0,0 +1,18 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.{yml,yaml}]
+indent_size = 2
+
+[{compose,docker-compose}.{yml,yaml}]
+indent_size = 4
diff --git a/webapp/.gitattributes b/webapp/.gitattributes
new file mode 100644
index 0000000..fcb21d3
--- /dev/null
+++ b/webapp/.gitattributes
@@ -0,0 +1,11 @@
+* text=auto eol=lf
+
+*.blade.php diff=html
+*.css diff=css
+*.html diff=html
+*.md diff=markdown
+*.php diff=php
+
+/.github export-ignore
+CHANGELOG.md export-ignore
+.styleci.yml export-ignore
diff --git a/webapp/.gitignore b/webapp/.gitignore
new file mode 100644
index 0000000..7be55e2
--- /dev/null
+++ b/webapp/.gitignore
@@ -0,0 +1,27 @@
+*.log
+.DS_Store
+.env
+.env.backup
+.env.production
+.phpactor.json
+.phpunit.result.cache
+/.codex
+/.cursor/
+/.idea
+/.nova
+/.phpunit.cache
+/.vscode
+/.zed
+/auth.json
+/node_modules
+/public/build
+/public/fonts-manifest.dev.json
+/public/hot
+/public/storage
+/storage/*.key
+/storage/pail
+/vendor
+_ide_helper.php
+Homestead.json
+Homestead.yaml
+Thumbs.db
diff --git a/webapp/README.md b/webapp/README.md
new file mode 100644
index 0000000..5ad1377
--- /dev/null
+++ b/webapp/README.md
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+## About Laravel
+
+Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
+
+- [Simple, fast routing engine](https://laravel.com/docs/routing).
+- [Powerful dependency injection container](https://laravel.com/docs/container).
+- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
+- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
+- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
+- [Robust background job processing](https://laravel.com/docs/queues).
+- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
+
+Laravel is accessible, powerful, and provides tools required for large, robust applications.
+
+## Learning Laravel
+
+Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
+
+In addition, [Laracasts](https://laracasts.com) contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
+
+You can also watch bite-sized lessons with real-world projects on [Laravel Learn](https://laravel.com/learn), where you will be guided through building a Laravel application from scratch while learning PHP fundamentals.
+
+## Agentic Development
+
+Laravel's predictable structure and conventions make it ideal for AI coding agents like Claude Code, Cursor, and GitHub Copilot. Install [Laravel Boost](https://laravel.com/docs/ai) to supercharge your AI workflow:
+
+```bash
+composer require laravel/boost --dev
+
+php artisan boost:install
+```
+
+Boost provides your agent 15+ tools and skills that help agents build Laravel applications while following best practices.
+
+## Contributing
+
+Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
+
+## Code of Conduct
+
+In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
+
+## Security Vulnerabilities
+
+If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
+
+## License
+
+The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
diff --git a/webapp/app/Console/Commands/RigCmdCommand.php b/webapp/app/Console/Commands/RigCmdCommand.php
new file mode 100644
index 0000000..a5e672c
--- /dev/null
+++ b/webapp/app/Console/Commands/RigCmdCommand.php
@@ -0,0 +1,30 @@
+argument('type'));
+ if (!in_array($type, ['skip', 'prev', 'pause', 'resume'], true)) {
+ $this->error('type must be one of: skip, prev, pause, resume');
+ return self::FAILURE;
+ }
+ try {
+ $ws->broadcast('mpd:cmd', ['type' => $type]);
+ } catch (Throwable $e) {
+ $this->error($e->getMessage());
+ return self::FAILURE;
+ }
+ $this->info(" → {$type}");
+ return self::SUCCESS;
+ }
+}
diff --git a/webapp/app/Console/Commands/RigLoadingCommand.php b/webapp/app/Console/Commands/RigLoadingCommand.php
new file mode 100644
index 0000000..83b001c
--- /dev/null
+++ b/webapp/app/Console/Commands/RigLoadingCommand.php
@@ -0,0 +1,101 @@
+loading();
+
+ $this->line('── Project Loading manifest ──');
+ $this->line(' (press Enter to keep [defaults])');
+ $this->line('');
+
+ $game = null;
+ $gameId = null;
+ $defaultGame = (string) ($prev['game'] ?? '');
+ while (true) {
+ $query = (string) $this->ask('Game (search)', $defaultGame ?: null);
+ if ($query === '') {
+ $this->error(' ✗ Game is required');
+ continue;
+ }
+ if ($twitch->enabled()) {
+ $cachedId = (string) ($prev['gameId'] ?? '');
+ if ($query === $defaultGame && preg_match('/^\d+$/', $cachedId)) {
+ $game = $defaultGame;
+ $gameId = $cachedId;
+ $this->line(" ↻ reusing cached: {$game} (id={$gameId})");
+ break;
+ }
+ try {
+ $hit = $twitch->searchCategory($query);
+ } catch (Throwable $e) {
+ $this->warn(' ! Twitch search failed: ' . $e->getMessage());
+ if ($this->confirm('Use the raw input without resolving an id?', true)) {
+ $game = $query;
+ break;
+ }
+ continue;
+ }
+ if ($hit === null) {
+ $this->warn(' ! no Twitch matches for "' . $query . '"');
+ continue;
+ }
+ $game = $hit['name'];
+ $gameId = $hit['id'];
+ $this->line(" ↳ matched: {$game} (id={$gameId})");
+ break;
+ }
+ $game = $query;
+ break;
+ }
+
+ $subtitle = (string) $this->ask('Subtitle (mode / episode / note)', $prev['subtitle'] ?? null);
+ $countdown = (int) $this->ask('Countdown (minutes)', (string) ($prev['countdownMin'] ?? 5));
+ $camera = $this->confirm('Camera', (bool) ($prev['camera'] ?? true));
+ $microphone = $this->confirm('Microphone', (bool) ($prev['microphone'] ?? true));
+
+ $data = [
+ 'compiledAt' => gmdate('Y-m-d\TH:i:s\Z'),
+ 'game' => $game,
+ 'gameId' => $gameId,
+ 'subtitle' => $subtitle ?: null,
+ 'countdownMin' => $countdown,
+ 'camera' => $camera,
+ 'microphone' => $microphone,
+ ];
+ $path = rtrim(config('rig.storage_data'), '/') . '/loading.json';
+ @mkdir(dirname($path), 0775, true);
+ file_put_contents(
+ $path,
+ json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"
+ );
+ $this->info('');
+ $this->info(" ✓ wrote {$path}");
+
+ // Push to Twitch — soft-fail so a network blip doesn't block the local manifest.
+ if (!$this->option('no-twitch') && $twitch->enabled() && $gameId) {
+ $title = $subtitle ?: $game;
+ try {
+ $twitch->setChannel($title, $gameId);
+ $this->info(" ✓ Twitch channel updated → \"{$title}\" / category {$game}");
+ } catch (Throwable $e) {
+ $this->warn(' ! Twitch sync failed (manifest still saved): ' . $e->getMessage());
+ }
+ }
+
+ $this->line('');
+ $this->line(' → refresh the Project Loading browser source in OBS.');
+ return self::SUCCESS;
+ }
+}
diff --git a/webapp/app/Console/Commands/RigPlaylistCommand.php b/webapp/app/Console/Commands/RigPlaylistCommand.php
new file mode 100644
index 0000000..1add435
--- /dev/null
+++ b/webapp/app/Console/Commands/RigPlaylistCommand.php
@@ -0,0 +1,125 @@
+warn(' ! no music dirs configured (set MUSIC_DIR_1 in .env)');
+ }
+
+ $ffprobe = (string) config('rig.ffprobe', '/usr/bin/ffprobe');
+ if (!is_executable($ffprobe)) {
+ $this->error(" ✗ ffprobe not found at {$ffprobe} (install ffmpeg or set FFPROBE_BIN)");
+ return self::FAILURE;
+ }
+
+ $this->line('── Indexing audio roots ──');
+ foreach ($roots as $r) {
+ $this->line(is_dir($r) ? " + {$r}" : " ! {$r} (missing — skipped)");
+ }
+
+ $tracks = [];
+ foreach ($roots as $root) {
+ if (!is_dir($root)) continue;
+ $finder = (new Finder())
+ ->files()
+ ->in($root)
+ ->name('/\.(' . implode('|', self::EXTS) . ')$/i')
+ ->ignoreUnreadableDirs()
+ ->sortByName();
+
+ foreach ($finder as $file) {
+ $name = $file->getFilename();
+ $base = $file->getFilenameWithoutExtension();
+ // Skip yt-dlp intermediates (e.g. foo.f140.m4a, foo.temp.opus).
+ if (preg_match('/\.(?:f\d+|temp|part)$/i', $base)) continue;
+
+ $path = $file->getRealPath();
+ $meta = $this->probe($ffprobe, $path);
+ $tracks[] = [
+ 'title' => $this->cleanTitle($base),
+ 'file' => 'file://' . $this->urlEncodePath($path),
+ 'durationSec' => isset($meta['durationSec']) ? (int) $meta['durationSec'] : null,
+ ];
+ }
+ }
+
+ $doc = [
+ 'syncedAt' => gmdate('Y-m-d\TH:i:s\Z'),
+ 'sourceDirs' => $roots,
+ 'trackCount' => count($tracks),
+ 'tracks' => $tracks,
+ ];
+ $path = rtrim(config('rig.storage_data'), '/') . '/playlist.json';
+ @mkdir(dirname($path), 0775, true);
+ file_put_contents(
+ $path,
+ json_encode($doc, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
+ );
+
+ $this->line('');
+ $this->info(" ✓ wrote {$path} ({$doc['trackCount']} tracks)");
+ $this->line(' → refresh the Music Daemon browser source in OBS to reload the queue.');
+ return self::SUCCESS;
+ }
+
+ private function probe(string $ffprobe, string $path): array
+ {
+ try {
+ $proc = new Process([
+ $ffprobe, '-v', 'error',
+ '-show_entries', 'format=duration:format_tags=title,artist',
+ '-of', 'json',
+ $path,
+ ]);
+ $proc->setTimeout(10);
+ $proc->run();
+ if (!$proc->isSuccessful()) return [];
+ $json = json_decode($proc->getOutput(), true) ?: [];
+ $fmt = $json['format'] ?? [];
+ return [
+ 'durationSec' => isset($fmt['duration']) ? (float) $fmt['duration'] : null,
+ ];
+ } catch (Throwable) {
+ return [];
+ }
+ }
+
+ /**
+ * Mirrors scripts/playlist.sh's clean_title():
+ * - drop "| ..." (or fullwidth |) tails (genre/label noise)
+ * - strip trailing YouTube IDs in brackets like "[-XxZTgMWKV0]"
+ * - strip "[NCS Release]" / "(NCS10 Release)" suffixes
+ */
+ private function cleanTitle(string $t): string
+ {
+ $t = preg_replace('/\s*[||].*$/u', '', $t) ?? $t;
+ $t = preg_replace('/\s*\[[A-Za-z0-9_-]{11}\]\s*$/', '', $t) ?? $t;
+ $t = preg_replace(
+ '/\s*[\[(](?:NCS\d*|No Copyright Sounds)(?:\s+Release)?[\])]\s*$/i',
+ '',
+ $t
+ ) ?? $t;
+ return trim($t);
+ }
+
+ private function urlEncodePath(string $path): string
+ {
+ // Same as Python's urllib.parse.quote(..., safe='/') — keep separators, encode the rest.
+ return implode('/', array_map('rawurlencode', explode('/', $path)));
+ }
+}
diff --git a/webapp/app/Console/Commands/RigSetupCommand.php b/webapp/app/Console/Commands/RigSetupCommand.php
new file mode 100644
index 0000000..433f123
--- /dev/null
+++ b/webapp/app/Console/Commands/RigSetupCommand.php
@@ -0,0 +1,84 @@
+error(" ✗ {$src} not found.");
+ $this->line(' Open OBS once with obs-websocket loaded so it generates the config.');
+ return self::FAILURE;
+ }
+ $cfg = json_decode((string) file_get_contents($src), true);
+ if (!is_array($cfg)) {
+ $this->error(" ✗ {$src} did not parse as JSON.");
+ return self::FAILURE;
+ }
+ $port = (int) ($cfg['server_port'] ?? 4455);
+ $pass = (string) ($cfg['server_password'] ?? '');
+ $url = "ws://localhost:{$port}";
+
+ $out = (string) config('rig.obs_config_js');
+ @mkdir(dirname($out), 0775, true);
+ $js = <<jsString($url)},
+ password: {$this->jsString($pass)},
+};
+
+JS;
+ file_put_contents($out, $js);
+ $this->info(" ✓ wrote {$out}");
+
+ // Mirror into .env so MusicCommandController / ObsWsClient can authenticate.
+ $this->writeEnv('OBS_WS_URL', $url);
+ $this->writeEnv('OBS_WS_PASSWORD', $pass);
+ $this->info(' ✓ updated .env OBS_WS_URL / OBS_WS_PASSWORD');
+
+ $this->line('');
+ $this->line(" url = {$url}");
+ $this->line(' password = ' . ($pass === '' ? '(none)' : '(set, ' . strlen($pass) . ' chars)'));
+ $this->line('');
+ $this->line(' → if obs-webapp is running under supervisord, restart it so the new env takes effect:');
+ $this->line(' sudo supervisorctl restart obs-webapp');
+
+ return self::SUCCESS;
+ }
+
+ private function jsString(string $s): string
+ {
+ return json_encode($s, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+ }
+
+ private function writeEnv(string $key, string $value): void
+ {
+ $env = base_path('.env');
+ $raw = is_file($env) ? file_get_contents($env) : '';
+ $line = $key . '=' . $this->escapeEnvValue($value);
+ if (preg_match("/^{$key}=.*$/m", $raw)) {
+ $raw = preg_replace("/^{$key}=.*$/m", $line, $raw);
+ } else {
+ $raw = rtrim($raw, "\n") . "\n" . $line . "\n";
+ }
+ file_put_contents($env, $raw);
+ }
+
+ private function escapeEnvValue(string $v): string
+ {
+ if ($v === '') return '';
+ if (preg_match('/[\s"#=]/', $v)) {
+ return '"' . str_replace('"', '\"', $v) . '"';
+ }
+ return $v;
+ }
+}
diff --git a/webapp/app/Console/Commands/RigTelemetryCommand.php b/webapp/app/Console/Commands/RigTelemetryCommand.php
new file mode 100644
index 0000000..3183619
--- /dev/null
+++ b/webapp/app/Console/Commands/RigTelemetryCommand.php
@@ -0,0 +1,42 @@
+option('collect') || !is_file($path)) {
+ $data = $snap->collect();
+ @mkdir(dirname($path), 0775, true);
+ file_put_contents(
+ $path,
+ json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n"
+ );
+ $this->info(" ✓ wrote {$path}");
+ } else {
+ $this->line(" · {$path} already exists — use --collect to re-read hardware.");
+ }
+
+ $current = $rig->telemetry();
+ $this->line('');
+ $this->line(" rig = " . ($current['rig'] ?? '?'));
+ $this->line(" cpu = " . ($current['cpu']['model'] ?? '?'));
+ if (!empty($current['gpu']['name'])) {
+ $this->line(" gpu = " . $current['gpu']['name']);
+ }
+ if (!empty($current['obs']['output']['w'])) {
+ $this->line(" output = {$current['obs']['output']['w']}×{$current['obs']['output']['h']} @ {$current['obs']['fps']} fps");
+ }
+ return self::SUCCESS;
+ }
+}
diff --git a/webapp/app/Http/Controllers/AudioController.php b/webapp/app/Http/Controllers/AudioController.php
new file mode 100644
index 0000000..3a94d6f
--- /dev/null
+++ b/webapp/app/Http/Controllers/AudioController.php
@@ -0,0 +1,71 @@
+query('p', '');
+ if ($b64 === '') abort(400, 'missing p');
+
+ // URL-safe base64; pad back to a multiple of 4 for strict decoding.
+ $padded = $b64 . str_repeat('=', (4 - strlen($b64) % 4) % 4);
+ $path = base64_decode(strtr($padded, '-_', '+/'), true);
+ if ($path === false || $path === '') abort(400, 'bad encoding');
+
+ $real = realpath($path);
+ if ($real === false || !is_file($real)) abort(404, 'file not found: ' . $path);
+
+ $allowed = false;
+ foreach ((array) config('rig.music_dirs') as $root) {
+ $rootReal = realpath($root);
+ if ($rootReal && str_starts_with($real . '/', rtrim($rootReal, '/') . '/')) {
+ $allowed = true;
+ break;
+ }
+ }
+ if (!$allowed) abort(403, 'outside allowed roots');
+
+ $ext = strtolower(pathinfo($real, PATHINFO_EXTENSION));
+ $mime = match ($ext) {
+ 'm4a', 'aac' => 'audio/mp4',
+ 'mp3' => 'audio/mpeg',
+ 'opus', 'ogg'=> 'audio/ogg',
+ 'flac' => 'audio/flac',
+ 'webm' => 'audio/webm',
+ 'wav' => 'audio/wav',
+ default => 'application/octet-stream',
+ };
+
+ // BinaryFileResponse handles Range requests automatically, which the
+ // HTML5