webapp: introduce Laravel app under webapp/ for scene overlays

Replaces the per-scene HTML directories (landing/, loading/, game/,
desktop/, goodbye/, music-box/, music/) with a single Laravel app
serving every overlay over HTTP. Supervisord runs `php artisan serve`
on 127.0.0.1:1118 and the OBS scene JSON now references HTTP routes
instead of file:// URLs.

Highlights:
 - public/css/hud.css consolidates the duplicated HUD chrome,
   scanlines/vignette/flicker, terminal styling, and pulse keyframes
   that were copy-pasted across all seven scenes.
 - Blade partials own hud-strip, crt-overlays, obs-ws-scripts,
   camera-frame, screen-frame; the seven scenes extend a shared
   overlay layout.
 - Artisan commands (`rig:setup`, `rig:telemetry`, `rig:loading`,
   `rig:playlist`, `rig:cmd`) replace the shell scripts that wrote
   per-rig JSON snapshots. TwitchHelix + HardwareSnapshot services
   handle the work the bash + Python helpers used to.
 - ObsWsClient + MusicCommandController kill the 250 ms cmd.js poll
   in the music daemon: POST /cmd/{skip|prev|pause|resume} opens a
   short-lived Pawl WS, authenticates, and broadcasts mpd:cmd.
 - AudioController streams files from the configured music dirs so
   CEF can load tracks under the HTTP origin (Chromium blocks
   HTTP-origin pages from loading file:// media).
 - DataController serves /data/playlist.js (with ETag mtime cache)
   and /cover.jpg (no-store) so the existing overlays' window.__PLAYLIST
   and cover.jpg cache-bust pattern keeps working.

scripts/obs-webapp.supervisord.conf is the supervisord unit; install
to /etc/supervisor.d/obs-webapp.conf.
scripts/rewrite-scene-urls.py is a one-shot tool that rewrites
basic/scenes/Default_Stream_HUD.json from file:// to HTTP URLs.
basic/scenes/Default_Stream_HUD.json.pre-webapp is the rollback
artifact (made with OBS closed; full pre-migration state).

The seven old scene directories, vendor/, and the bash scripts are
still on disk pending visual verification; the next commit will
prune them.
This commit is contained in:
Jakub Zych
2026-05-21 12:47:10 +02:00
parent c8f9c11c93
commit 059f069ef4
85 changed files with 19180 additions and 49 deletions

View File

@@ -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": {