Commit graph

570 commits

Author SHA1 Message Date
claude
53196d38ce feat(scheduler): recorder scheduling — UI, CRUD, tick loop, recurrence
- New Ingest → Schedule page: upcoming/past/all tabs, status badges
  (pending / recording / completed / cancelled / failed), 10s
  auto-refresh, cancel/delete actions
- New Schedule modal: name, recorder dropdown, datetime-local start/end,
  recurrence (one-shot / daily / weekly), sensible defaults (+5min / +35min)
- Backend: migration 009 (recorder_schedules), routes/schedules.js
  (list/create/edit/cancel/delete), scheduler.js tick loop polling every
  15s; transitions trigger /recorders/:id/start and /stop via in-process
  HTTP so we reuse the full container orchestration path
- Recurring schedules: tick loop auto-queues the next occurrence on
  completion (daily = +24h, weekly = +7d)
- Sidebar + app.jsx route wired in, schedule-row table style added
2026-05-23 03:19:24 +00:00
claude
6398879b56 feat: SDK deployment UI, proxy encoding global settings, S3 env fallback
- Settings: drop AMPP tab, rename GPU/Transcoding → Proxy encoding
  with explicit 'applied to every ingested file' wording, expose
  CPU codec/preset options when GPU is off
- New Capture SDKs tab (Settings): upload Blackmagic / AJA / Deltacast
  SDK archives (.zip / .tar.gz) staged to /sdk/<vendor>/ inside mam-api;
  BMD is fully wired into the FFmpeg build pipeline, AJA + Deltacast
  staging-only pending FFmpeg patches
- mam-api: new /api/v1/sdk routes (multer upload, extract, list, delete);
  Dockerfile gets unzip+tar; docker-compose mounts /mnt/NVME/MAM/sdk:/sdk
- proxy worker now reads proxy-encoding settings from DB on every job,
  builds args for libx264 / NVENC / VAAPI, falls back to libx264 on
  hardware-encode failure
- settings GET /s3 falls back to S3_* env vars when DB is empty so the
  UI reflects what's actually wired (fixes 'not configured' false alarm)
2026-05-23 02:58:32 +00:00
328f7b4f31 feat: live HLS preview, proxy worker fixes, Settings tabs, growing-files + Premier panel
- worker/proxy: scale-to-even filter, analyzeduration 100M, skip images, hasAudio
- worker/promotion: SMB landing zone -> S3 on idle, queues proxy job, status='ready'
- web-ui screens-ingest: HlsPreview component replaces fake LiveStrip/FauxFrame
- web-ui screens-admin: functional Settings tabs (S3, GPU, Growing, SDI, AMPP)
- mam-api /settings/growing: GET/PUT growing-files config
- mam-api /assets/:id/live-path: SMB UNC/POSIX path for live growing assets
- capture-manager: GROWING_ENABLED -> write hires to /growing instead of S3 stream
- recorders.js: pass GROWING_ENABLED to capture container, bind /growing mount
- docker-compose: mount /mnt/NVME/MAM/wild-dragon-growing on mam-api + worker
- premiere-plugin: Mount Live button, Relink-to-HiRes, live->ready status poll
2026-05-22 19:12:53 -04:00
3fc8fbc230 add per-seat/per-stream/per-month strikethrough hero to Tokens page 2026-05-22 17:29:23 -04:00
ceceedf201 probe fallback: basic TCP/UDP connectivity when capture service is offline 2026-05-22 17:26:26 -04:00
4864db03f3 probe: fallback to basic TCP/UDP connectivity check when capture service is offline 2026-05-22 17:22:30 -04:00
8b57a9a35a expand codec list, add MXF container, remove proxy settings (fixed profile) 2026-05-22 17:20:01 -04:00
fa787bbe1e fix hover-to-play: remove status filter so any asset triggers stream fetch 2026-05-22 17:18:56 -04:00
0aa0922fd3 remove hardcoded recorders badge 2026-05-22 17:18:20 -04:00
1abf22623d feat: hover-to-play video preview on library asset cards
Fetches stream URL on hover after 350ms delay; renders muted autoplay
video overlay over the thumbnail. Supports both mp4 and HLS streams.
Only triggers for ready/live assets to avoid pointless API calls.
2026-05-22 16:58:11 -04:00
4afd0c7b21 feat: add /cluster/containers endpoint via Docker socket
Lists all containers on the local host; supports POST /containers/:id/restart.
Falls back to [] gracefully if Docker socket is unavailable.
2026-05-22 16:57:33 -04:00
6f2de45819 feat: wire real video playback via GET /assets/:id/stream
- Fetch stream URL on asset open; show <video> element for mp4/hls
- Use hls.js for live HLS streams (loaded via CDN in index.html)
- Sync video play/pause/seek/timeupdate to React state
- Show loading state while fetching stream, status message when unavailable
- Add Retry processing button for error-status assets
- totalMs derived from video metadata when available, falls back to parseDuration
2026-05-22 13:37:55 -04:00
e3c3d60103 index: add hls.js for live stream HLS playback 2026-05-22 13:31:57 -04:00
81324c8e52 shell: add Field component (used by modal-new-recorder, was missing from global scope) 2026-05-22 12:56:33 -04:00
bec58ab138 screens-asset: fix thumbGrad crash, parseDuration NaN, guard missing ACTIVITY 2026-05-22 12:49:33 -04:00
451bed834f screens-admin: wire all buttons — invite user, export CSV, cluster refresh, container logs/restart, node drain/remove 2026-05-22 12:27:02 -04:00
d00e1c666e screens-ingest: wire delete button on RecorderRow 2026-05-22 12:24:10 -04:00
ddb4cf0c51 feat: add POST /jobs/:id/retry endpoint for re-queuing failed BullMQ jobs 2026-05-22 12:18:53 -04:00
fea0f2962b fix: wire Jobs Retry (POST /jobs/:id/retry) and Delete (DELETE /jobs/:id) buttons 2026-05-22 12:18:23 -04:00
506ee2d695 fix: wire New Project button — modal + POST /projects + state refresh 2026-05-22 12:17:54 -04:00
88689a4eb2 fix: wire Library Upload button to navigate to Upload screen 2026-05-22 12:17:29 -04:00
dc269bec00 fix: make Settings S3 form functional — load from API, save & test 2026-05-22 12:08:10 -04:00
665ab5238d feat: live status polling in RecorderRow, immediate refresh on mount 2026-05-22 11:35:13 -04:00
bb508d3256 feat: add probe button to SRT/RTMP sources, fix node labels 2026-05-22 11:33:45 -04:00
994fd799d0 fix: stop endpoint handles missing/dead containers gracefully 2026-05-22 11:32:44 -04:00
6510871448 fix: implement real upload (XHR + S3 multipart) and fix SDI recorder device_index + manual fallback: modal-new-recorder.jsx 2026-05-22 11:10:01 -04:00
26399f8d0a fix: implement real upload (XHR + S3 multipart) and fix SDI recorder device_index + manual fallback: screens-ingest.jsx 2026-05-22 11:10:00 -04:00
529d14cb6b fix: SDI crash, monitors polling, home RAM fields, editor IN DEV splash, timecode, create recorder API: modal-new-recorder.jsx 2026-05-22 10:55:22 -04:00
fb44bd8aff fix: SDI crash, monitors polling, home RAM fields, editor IN DEV splash, timecode, create recorder API: screens-editor.jsx 2026-05-22 10:55:20 -04:00
24a1d57165 fix: SDI crash, monitors polling, home RAM fields, editor IN DEV splash, timecode, create recorder API: screens-ingest.jsx 2026-05-22 10:55:19 -04:00
48ee66e744 fix: SDI crash, monitors polling, home RAM fields, editor IN DEV splash, timecode, create recorder API: screens-home.jsx 2026-05-22 10:55:18 -04:00
0342aa0a5a fix admin screen: move data destructuring inside components, normalize field names: screens-admin.jsx 2026-05-22 10:15:42 -04:00
406f28c663 feat(ui): wire ingest screens to real API (recorders, capture devices): screens-ingest.jsx 2026-05-22 10:07:13 -04:00
835545e061 feat(ui): wire library, jobs, ingest, editor screens to live API data: screens-editor.jsx 2026-05-22 10:05:57 -04:00
1392e28a88 feat(ui): wire library, jobs, ingest, editor screens to live API data: screens-jobs.jsx 2026-05-22 10:05:56 -04:00
bc03ee866b feat(ui): wire library, jobs, ingest, editor screens to live API data: screens-library.jsx 2026-05-22 10:05:54 -04:00
69f0d130ee feat(ui): wire screens to live API data; add thumbnail lazy-loading: screens-projects.jsx 2026-05-22 10:04:25 -04:00
07af51b05c feat(ui): wire screens to live API data; add thumbnail lazy-loading: screens-home.jsx 2026-05-22 10:04:24 -04:00
3574ae8a43 feat(ui): wire screens to live API data; add thumbnail lazy-loading: visuals.jsx 2026-05-22 10:04:23 -04:00
7dda7cc89c feat(ui): wire data.jsx to real API; add loading gate in app.jsx: app.jsx 2026-05-22 10:02:55 -04:00
98025001e8 feat(ui): wire data.jsx to real API; add loading gate in app.jsx: data.jsx 2026-05-22 10:02:54 -04:00
068e3a0828 fix(ui): replace FauxFrame SVG scenes with clean dark placeholder; strip fake LiveStrip animation: screens-editor.jsx 2026-05-22 09:31:58 -04:00
6ad277275b fix(ui): replace FauxFrame SVG scenes with clean dark placeholder; strip fake LiveStrip animation: visuals.jsx 2026-05-22 09:31:57 -04:00
f58fe95f0d fix(ui): remove placeholder elements — no scanlines, no DEV BUILD, no tweaks panel: screens-projects.jsx 2026-05-22 09:30:50 -04:00
6e763e8270 fix(ui): remove placeholder elements — no scanlines, no DEV BUILD, no tweaks panel: screens-home.jsx 2026-05-22 09:30:49 -04:00
6ac3050a05 fix(ui): remove placeholder elements — no scanlines, no DEV BUILD, no tweaks panel: index.html 2026-05-22 09:30:47 -04:00
e13d111b9f feat(ui): Dragonflight redesign — admin screens (users, tokens, containers, cluster, settings): screens-admin.jsx 2026-05-22 08:24:08 -04:00
1eaf9dff5c Add Z-AMPP UI: screens-ingest + screens-admin: screens-admin.jsx 2026-05-22 08:22:38 -04:00
20dfa504e5 Add Z-AMPP UI: screens-ingest + screens-admin: screens-ingest.jsx 2026-05-22 08:22:37 -04:00
0945f488f6 feat(ui): Dragonflight redesign — ingest, jobs, editor, admin screens: screens-ingest.jsx 2026-05-22 08:20:15 -04:00
bd9dfd2cce Add Z-AMPP UI: screens-jobs + screens-editor + modal-new-recorder: modal-new-recorder.jsx 2026-05-22 08:19:03 -04:00
b8e1796c33 Add Z-AMPP UI: screens-jobs + screens-editor + modal-new-recorder: screens-editor.jsx 2026-05-22 08:19:02 -04:00
f8bd80e38e Add Z-AMPP UI: screens-jobs + screens-editor + modal-new-recorder: screens-jobs.jsx 2026-05-22 08:19:01 -04:00
7007d2df93 Add Z-AMPP UI: screens-asset + screens-projects: screens-asset.jsx 2026-05-22 08:17:17 -04:00
ed3084e60f feat(ui): Dragonflight redesign — screen components batch 1: screens-projects.jsx 2026-05-22 08:17:06 -04:00
4a77c1bed8 Add Z-AMPP UI: screens-home + screens-library: screens-library.jsx 2026-05-22 08:15:36 -04:00
100fc054cc Add Z-AMPP UI: screens-home + screens-library: screens-home.jsx 2026-05-22 08:15:35 -04:00
c0345e47c9 feat(ui): Dragonflight redesign — visuals + tweaks panel: visuals.jsx 2026-05-22 08:15:34 -04:00
a9e0313fe4 Add Z-AMPP UI: visuals + tweaks-panel: tweaks-panel.jsx 2026-05-22 08:13:37 -04:00
d54d960b8f Add Z-AMPP UI: visuals + tweaks-panel: visuals.jsx 2026-05-22 08:13:36 -04:00
2706903353 feat(ui): Dragonflight redesign — foundation JSX files: app.jsx 2026-05-22 08:13:03 -04:00
b6dcecb672 feat(ui): Dragonflight redesign — foundation JSX files: shell.jsx 2026-05-22 08:13:02 -04:00
14bfcabcaf feat(ui): Dragonflight redesign — foundation JSX files: icons.jsx 2026-05-22 08:13:01 -04:00
3b1610a167 feat(ui): Dragonflight redesign — foundation JSX files: data.jsx 2026-05-22 08:13:00 -04:00
d5fd705d66 feat(web-ui): Z-AMPP core JSX files (data, icons, visuals, tweaks, shell, app): icons.jsx 2026-05-22 08:09:04 -04:00
a700124f50 feat(web-ui): Z-AMPP core JSX files (data, icons, visuals, tweaks, shell, app): data.jsx 2026-05-22 08:09:03 -04:00
10952df591 feat(web-ui): add styles-asset and styles-rest CSS: styles-rest.css 2026-05-22 08:07:16 -04:00
352d21496f feat(web-ui): asset detail + rest CSS: styles-rest.css 2026-05-22 08:06:40 -04:00
016adff949 feat(web-ui): asset detail + rest CSS: styles-asset.css 2026-05-22 08:06:39 -04:00
6befb0f46a feat(web-ui): Z-AMPP screen + component CSS: styles-modal.css 2026-05-22 08:03:57 -04:00
e655ccdf64 feat(web-ui): Z-AMPP screen + component CSS: styles-screens.css 2026-05-22 08:03:55 -04:00
2c88fb0a03 feat(web-ui): Z-AMPP design system CSS: styles-fixes.css 2026-05-22 08:02:36 -04:00
7b13d8bd0f feat(web-ui): Z-AMPP design system CSS: styles.css 2026-05-22 08:02:35 -04:00
68df3797f1 feat(web-ui): new design system CSS from Claude Design: styles.css 2026-05-22 08:02:07 -04:00
dccca554e0 Add Dragonflight React SPA design - index.html and CSS: styles-fixes.css 2026-05-21 23:53:21 -04:00
1b63429def Add Dragonflight React SPA design - index.html and CSS: index.html 2026-05-21 23:53:19 -04:00
87da3c0b58 feat: migrate cluster.html to wd-* design system 2026-05-21 23:17:48 -04:00
06551c66a6 feat: migrate editor.html to wd-* design system 2026-05-21 23:16:46 -04:00
136820c8f9 feat: migrate capture.html to wd-* design system 2026-05-21 23:16:29 -04:00
7c88692c1c feat: migrate recorders.html to wd-* design system 2026-05-22 03:16:27 +00:00
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
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
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
447b2b2b81 web-ui: add _primitives-smoke.html for wave-1 visual QA
Delete at end of wave 4 once every shell page has migrated to the new primitives.
2026-05-21 12:43:00 -04:00
3b89cf2d5f web-ui: fix wave-1 build pipeline (primitives missing from bundle)
Three bugs found during task 20 verify, all fixed:

1. Tailwind CLI does NOT read postcss.config.js. Switched Dockerfile to
   npx postcss + postcss-cli so the postcss plugin chain actually runs.

2. postcss-import was not installed but app.css uses @import for the
   primitive component files. Added postcss-import + cssnano (for prod
   minification under --env production).

3. @import statements must come BEFORE any other rules per CSS spec.
   app.css had @tailwind base/components ABOVE @import, so postcss-import
   silently skipped every component @import. Moved all @imports to the
   top, @tailwind directives below. Bundle went from 121KB with 0 wd-*
   classes to 138KB with 116 wd-* classes.

Also added tailwind safelist for wd-/is-/nav-dev-badge so the wave-2
migration of HTML files cannot accidentally tree-shake primitives.
2026-05-21 16:41:55 +00:00
f9236101b9 web-ui: wave-1 finish — self-host fonts + multi-stage Dockerfile
Fonts: Inter 400/500/600 + JetBrains Mono 400/600 (woff2 from rsms/inter and JetBrains/JetBrainsMono github).

Dockerfile: two-stage build. Stage 1 (node:20-alpine) runs tailwindcss --minify to emit public/dist/app.css. Stage 2 (nginx:alpine) ships the static result.

NOTE on task 19 (nginx caching for /dist /fonts): SKIPPED. The existing nginx.conf already caches *.css and *.woff2 for 1y immutable via the generic location ~* \\.(css|...|woff2|...)$ regex. Adding explicit /dist/ and /fonts/ blocks would be redundant.
2026-05-21 16:32:55 +00:00
6561cecf33 web-ui: fix corrupted .gitignore from earlier patch 2026-05-21 12:31:18 -04:00
a4bb6e7b0c web-ui: add node_modules + public/dist to .gitignore for wave-1 build 2026-05-21 12:30:56 -04:00
1f995c9029 web-ui: wave-1 foundation — services/web-ui/tailwind.config.js 2026-05-21 12:30:41 -04:00
891a8f82b7 web-ui: wave-1 foundation — services/web-ui/src/css/components/topbar.css 2026-05-21 12:30:40 -04:00
23ae848f5b web-ui: wave-1 foundation — services/web-ui/src/css/components/tokens.css 2026-05-21 12:30:40 -04:00
a16c235f71 web-ui: wave-1 foundation — services/web-ui/src/css/components/toast.css 2026-05-21 12:30:39 -04:00
e56704b69f web-ui: wave-1 foundation — services/web-ui/src/css/components/slide-panel.css 2026-05-21 12:30:39 -04:00
1c0ed05ac9 web-ui: wave-1 foundation — services/web-ui/src/css/components/sidebar.css 2026-05-21 12:30:38 -04:00
a6c9f88068 web-ui: wave-1 foundation — services/web-ui/src/css/components/motion.css 2026-05-21 12:30:38 -04:00
310eca0810 web-ui: wave-1 foundation — services/web-ui/src/css/components/list-row.css 2026-05-21 12:30:38 -04:00
a76e6b9a81 web-ui: wave-1 foundation — services/web-ui/src/css/components/form-controls.css 2026-05-21 12:30:37 -04:00
836a163cc8 web-ui: wave-1 foundation — services/web-ui/src/css/components/field-group.css 2026-05-21 12:30:37 -04:00
052a880b0f web-ui: wave-1 foundation — services/web-ui/src/css/components/empty-state.css 2026-05-21 12:30:36 -04:00
2f3e04cfc3 web-ui: wave-1 foundation — services/web-ui/src/css/components/card-operational.css 2026-05-21 12:30:36 -04:00
080f82e198 web-ui: wave-1 foundation — services/web-ui/src/css/components/card-asset.css 2026-05-21 12:30:36 -04:00
c08025eeb2 web-ui: wave-1 foundation — services/web-ui/src/css/components/button.css 2026-05-21 12:30:35 -04:00
30cb6663dd web-ui: wave-1 foundation — services/web-ui/src/css/components/badge.css 2026-05-21 12:30:35 -04:00
e256a771d5 web-ui: wave-1 foundation — services/web-ui/src/css/app.css 2026-05-21 12:30:34 -04:00
3df6a4434e web-ui: wave-1 foundation — services/web-ui/postcss.config.js 2026-05-21 12:30:34 -04:00
9d99811272 web-ui: wave-1 foundation — services/web-ui/package.json 2026-05-21 12:30:33 -04:00