Commit graph

581 commits

Author SHA1 Message Date
1e0015322c feat: migrate projects.html to wd-* design system 2026-05-21 23:15:57 -04:00
6176791174 feat: migrate player.html to wd-* design system 2026-05-21 23:15:18 -04:00
9ff80f8cc1 feat: migrate upload.html to wd-* design system 2026-05-21 23:14:51 -04:00
738d6298d2 feat: migrate edit.html to wd-* design system 2026-05-21 23:14:19 -04:00
a84bc3ecfe feat: migrate api-tokens.html to wd-* design system 2026-05-21 23:14:09 -04:00
daa203a43e feat: migrate index.html to wd-* design system 2026-05-21 23:13:13 -04:00
33d2a4004d feat: migrate jobs.html to wd-* design system 2026-05-21 23:12:58 -04:00
6e43ab30c2 rebrand: Recorders — Dragonflight, ember orange hue-32 2026-05-22 02:54:10 +00:00
cc45cc6347 rebrand: _primitives-smoke — Dragonflight brand 2026-05-21 22:52:12 -04:00
c31933a53c rebrand: Projects — Dragonflight, ember orange hue-32 2026-05-21 22:51:20 -04:00
efe005378a rebrand: Editor (in development) — Dragonflight, ember orange hue-32 2026-05-21 22:49:43 -04:00
5874c93956 rebrand: Editor — Dragonflight, ember orange hue-32 2026-05-21 22:49:00 -04:00
cd5fc3a05c rebrand: upload.html — Dragonflight title + sidebar 2026-05-21 22:44:25 -04:00
e0a2d0c95c rebrand: jobs.html — Dragonflight title + sidebar 2026-05-21 22:42:56 -04:00
4572c88f58 rebrand: capture.html — Dragonflight title + sidebar + hue-32 2026-05-21 22:40:48 -04:00
c752227e20 rebrand: api-tokens.html — Dragonflight title + sidebar 2026-05-21 22:39:20 -04:00
d4e5af459e rebrand: settings.html — Z-AMPP → Dragonflight 2026-05-21 22:35:33 -04:00
29360e38e8 rebrand: users.html — Z-AMPP → Dragonflight 2026-05-21 22:33:21 -04:00
e5f4c00729 rebrand: containers.html — Z-AMPP → Dragonflight 2026-05-21 22:31:41 -04:00
c6aeedb5fc rebrand: Dragonflight — cluster.html brand names 2026-05-21 22:27:36 -04:00
32cf6bf63e rebrand: Dragonflight — tokens.html brand names and footer text 2026-05-21 22:26:24 -04:00
024833cc95 rebrand: Dragonflight — login.html brand names, description text 2026-05-21 22:22:58 -04:00
b4642b3c78 rebrand: Dragonflight — index.html brand names, splash screen, accent colors 2026-05-21 22:22:12 -04:00
b82cc73cf1 rebrand: Dragonflight — home.html wordmark, accent gradients, brand names 2026-05-21 22:19:00 -04:00
873920d27f rebrand: Dragonflight — ember orange accent (hue 266→32) 2026-05-21 22:16:32 -04:00
37767f9939 fix(cluster): pickIp() only treats 172.17.x as docker bridge, not all of RFC1918 172.16/12 2026-05-21 21:27:15 -04:00
00f3f2905f feat(cluster): expose db/redis ports for worker-node connectivity 2026-05-21 21:23:23 -04:00
30b4deffc6 fix(capture): proper SDK 16 patch via upstream FFmpeg master diff
The previous patch_decklink.py mixed v14_2_1 versioned types (Fix 1 renamed the allocator class) with no-ops for SetVideoInputFrameMemoryAllocator + QueryInterface-around-GetBytes (Fixes 2 & 3). That inconsistency compiled but silently dropped every video frame: VideoInputFrameArrived saw _v14_2_1 allocator output but tried to read it via the SDK 16 unversioned IDeckLinkVideoBuffer path, and the SDK released the buffer before FFmpeg could consume it.

Bisected with the BMD-provided Capture sample at SDK 16 mode 5 (Hp29) which got frames cleanly, confirming the signal was fine and the bug was in FFmpegs decklink demuxer.

Fix: pull libavdevice/decklink_{enc,dec,common}{.cpp,.h} from upstream FFmpeg master (commits past 7.1 that fully rename every decklink interface to its _v14_2_1 versioned form) and apply that diff in reverse during build. Now build is internally consistent and frames flow.

Verified: SDI1 recorder on zampp2 hits 423 frames in 14s @ 29 fps, ProRes HQ at 91 Mbps.
2026-05-22 00:53:03 +00:00
96f0f58e68 capture: yadif deint=1 so progressive SDI passes through unchanged
Bug: yadif=mode=1 unconditionally doubled output framerate for SDI input. On 1080p29.97 progressive sources the encoder produced zero frames (time advanced, size stayed at 1KiB MOV header).

Fix: deint=1 makes yadif only process frames flagged as interlaced; progressive frames pass through at the source rate.
2026-05-22 00:14:02 +00:00
a8656fc1a8 capture: custom FFmpeg 7.1 build with DeckLink + D-Bus mounts + SDI deinterlace
Dockerfile is now a two-stage build that compiles FFmpeg from source with --enable-decklink against the Blackmagic SDK 16.x headers in services/capture/sdk/ (operator-supplied, gitignored). build-with-decklink.sh + patch_decklink.py drive the build.

docker-compose.yml mounts /dev/shm, /run/dbus, /run/systemd into mam-api, capture, web-ui so the BMD runtime can talk to the host.

capture-manager.js wraps SDI sources with -vf yadif=mode=1 (deinterlace).

recorders.html defaults to SDI source type now that we have a working DeckLink path.
2026-05-22 00:01:43 +00:00
1074104d34 fix(capture): FFmpeg 7.x DeckLink compatibility 2026-05-22 00:00:02 +00:00
486e3c27e4 fix(decklink): mount /dev/blackmagic in sidecar + remote node routing via node-agent
Two bugs fixed:
1. SDI capture sidecar never had /dev/blackmagic bound — ffmpeg opened the
   decklink input inside a container with no device nodes, so frame=0.
   Fix: local spawns now push '/dev/blackmagic:/dev/blackmagic' onto Binds
   when source_type='sdi'.

2. recorders.js always spawned sidecars against the local Docker socket
   (zampp1), even when a recorder's node_id pointed at zampp2 (where the
   card is). Fix: resolveNodeTarget() looks up the recorder's cluster node;
   if it's a different hostname the sidecar is spawned via a new
   POST /sidecar/start endpoint on the remote node-agent.

node-agent gains three new routes (all talk to the local Docker socket):
  POST   /sidecar/start         — create + start container (host network,
                                   privileged, /dev/blackmagic bind for sdi)
  DELETE /sidecar/:id           — stop + remove
  GET    /sidecar/:id/status    — inspect + poll capture service

docker-compose.worker.yml: add /var/run/docker.sock and LIVE_DIR to
node-agent so it can spawn sidecars, and document build-capture prerequisite.: docker-compose.worker.yml
2026-05-21 18:51:11 -04:00
bbed2a7059 fix(decklink): mount /dev/blackmagic in sidecar + remote node routing via node-agent
Two bugs fixed:
1. SDI capture sidecar never had /dev/blackmagic bound — ffmpeg opened the
   decklink input inside a container with no device nodes, so frame=0.
   Fix: local spawns now push '/dev/blackmagic:/dev/blackmagic' onto Binds
   when source_type='sdi'.

2. recorders.js always spawned sidecars against the local Docker socket
   (zampp1), even when a recorder's node_id pointed at zampp2 (where the
   card is). Fix: resolveNodeTarget() looks up the recorder's cluster node;
   if it's a different hostname the sidecar is spawned via a new
   POST /sidecar/start endpoint on the remote node-agent.

node-agent gains three new routes (all talk to the local Docker socket):
  POST   /sidecar/start         — create + start container (host network,
                                   privileged, /dev/blackmagic bind for sdi)
  DELETE /sidecar/:id           — stop + remove
  GET    /sidecar/:id/status    — inspect + poll capture service

docker-compose.worker.yml: add /var/run/docker.sock and LIVE_DIR to
node-agent so it can spawn sidecars, and document build-capture prerequisite.: recorders.js
2026-05-21 18:51:10 -04:00
8186b181cc fix(decklink): mount /dev/blackmagic in sidecar + remote node routing via node-agent
Two bugs fixed:
1. SDI capture sidecar never had /dev/blackmagic bound — ffmpeg opened the
   decklink input inside a container with no device nodes, so frame=0.
   Fix: local spawns now push '/dev/blackmagic:/dev/blackmagic' onto Binds
   when source_type='sdi'.

2. recorders.js always spawned sidecars against the local Docker socket
   (zampp1), even when a recorder's node_id pointed at zampp2 (where the
   card is). Fix: resolveNodeTarget() looks up the recorder's cluster node;
   if it's a different hostname the sidecar is spawned via a new
   POST /sidecar/start endpoint on the remote node-agent.

node-agent gains three new routes (all talk to the local Docker socket):
  POST   /sidecar/start         — create + start container (host network,
                                   privileged, /dev/blackmagic bind for sdi)
  DELETE /sidecar/:id           — stop + remove
  GET    /sidecar/:id/status    — inspect + poll capture service

docker-compose.worker.yml: add /var/run/docker.sock and LIVE_DIR to
node-agent so it can spawn sidecars, and document build-capture prerequisite.: index.js
2026-05-21 18:51:09 -04:00
539429c058 tokens.html: remove orphan sidebar-footer + duplicate /nav; use main flex wrapper 2026-05-21 16:40:28 -04:00
01a9d6c3db settings.html: remove orphan sidebar-footer + duplicate /nav; use main flex wrapper 2026-05-21 16:40:28 -04:00
Zac
ddd3b3eca1 Revert shell.css primitive rework (5 commits eea1ed6..a8f5bce) 2026-05-21 20:34:08 +00:00
a8f5bce9ee home.html: drop per-page body+shell rules (now in shell primitive) 2026-05-21 16:22:49 -04:00
683f0ff101 containers.html: drop inline shell hack (now in shell primitive) 2026-05-21 16:22:49 -04:00
47c0e1f933 users.html: drop inline shell hack (now in shell primitive) 2026-05-21 16:22:48 -04:00
6cad11f687 app.css: import new shell primitive; drop redundant html base rule (now in shell.css) 2026-05-21 16:22:47 -04:00
eea1ed6bcb shell.css: codify body + .wd-shell + .wd-main as a primitive (fix dead-space layout bug) 2026-05-21 16:22:46 -04:00
c6bcbbd214 web-ui(wave 2): migrate settings.html to new primitives
Surgical migration: stylesheet swap to /dist/app.css + sidebar markup
updated to wd-sidebar primitives. Page-specific content + JS unchanged.
2026-05-21 13:35:04 -04:00
e7495dfe29 web-ui(wave 2): migrate tokens.html to new primitives
Surgical migration: stylesheet swap to /dist/app.css + sidebar markup
updated to wd-sidebar primitives. Page-specific content + JS unchanged.
2026-05-21 13:35:03 -04:00
5650b279c3 web-ui(wave 2): migrate users.html to new primitives 2026-05-21 13:33:22 -04:00
596fe228ed web-ui(wave 2): migrate containers.html to new primitives 2026-05-21 13:33:22 -04:00
e0cfe80a9e web-ui(wave 2): migrate home.html to new primitives
Swap stylesheet to /dist/app.css. Sidebar markup ported to wd-sidebar /
wd-nav-item / wd-sidebar-* primitives (active state = leading accent dot).
Logout button promoted to wd-btn--ghost--sm--icon.

Hero (portrait, wordmark, tagline) and the 10 illustrated cards keep
their bespoke design — they're a brand moment. Hardcoded oklch values
in the inline style replaced with var(--accent-bright), var(--signal-bad),
var(--bg-base), var(--accent-border), var(--overlay), etc. wherever the
brand palette already provides them.

All JS ids preserved (assetCount, projectCount, recorderCount,
containerCount, nodeCount, jobCount, ingestCount, captureStatus,
tokenBurn, userAvatar, userName, userRole, logoutBtn, systemBuild).
loadStats() poll cycle unchanged.
2026-05-21 13:19:16 -04:00
16a34a2fad web-ui(wave 2): migrate login.html to new primitives
Keeps the hero + AMPP Safe stamp + brand panel. Right column now uses
wd-form-group / wd-input / wd-label / wd-btn primitives loaded from
/dist/app.css. All JS ids and handlers preserved verbatim (login-form,
setup-form, flash, show-setup, show-login).

Visual changes: tighter form spacing, focus rings use accent-subtle
ring, flash messages use the top-strip toast pattern.
2026-05-21 13:09:39 -04:00
75b94a5025 web-ui(wave 2): token cleanups from wave-1 code review
Promoted 14 new tokens (--accent-hover, --signal-{good,bad,warn}-hover,
--accent-bright, --thumb-black, --overlay, --shadow, --ease-out-{quart,expo},
--dur-{fast,normal,slide}, --z-topbar) and substituted every raw oklch /
cubic-bezier / hardcoded z-index occurrence in the 12 primitive files.

cubic-bezier appearances dropped from 8 files to 0 (only in tokens.css).
Bundle byte count: 138 KB -> 139 KB. Visual regression: zero (smoke page
still renders identically).
2026-05-21 17:08:02 +00:00
265f4174d5 docs: UI shell rework wave-2 implementation plan
7 tasks: token cleanups from wave-1 review (task 0), then migrate login/home/settings/tokens/users/containers.html one-by-one with deploy-and-verify between each. Smallest blast radius first.
2026-05-21 13:06:04 -04:00