Back to the resultsSource: night-2026-10-11/PUNCHLIST.md

LightDesk v2 punchlist, lane C UX walk, 2026-10-11

Subject: branch two-screen at head 4dbe8af. Pages: desk.html (screen 1, 1536x864), screen2.html (screen 2, 1920x1080), index.html (phone, 390x844 and 844x390).

Method: git archive 4dbe8af into a scratch folder, built, dry run --dry-run --ui-standalone --port 7082 with its own data home (nothing written to the repo, /api/dmx/nodes never called). Headless bundled Chromium, DPR 1. Every number below comes from getBoundingClientRect, getComputedStyle, scroll sizes, a live API read, or a pixel probe of a PNG. Views measured: screen 1 idle, with M2 picked, with CHORUS live; screen 2 with nothing picked, one spot (M2), three pars, CHORUS live; phone at both sizes, top and scrolled 1200 px.

Owners: S1 = desk., api.js, controls.js, sync.js, tokens.css. S2 = screen2., inspector.js, wall.js, save.js. S3 = new phone.html. D = PC launch (two-screen.ps1), outside the three UI lanes.

Summary

Rank Count
P0, breaks or misleads a live operator 5
P1, slows the operator 11
P2, polish 13

Clean results: zero page scroll on screen 1 and screen 2 at every view (document 1536x864 and 1920x1080 exactly). Zero visible targets under 44 px on screen 1 (236 controls) and screen 2 (199 to 271 controls). No console errors on any page. Every key hint printed on screen 1 is bound (Esc, B, C, 1 to =, Shift+1 to Shift+=, 27 hints). The screen 2 inspector for a spot is linear throughout: hue row, pale-to-deep row, colour wheel slots in a row, gobo slots in rows, beam sliders.

P0

# Page Selector Measured Fix in one sentence Owner
P0-1 Screen 1 #closeBtn (twoTap, controls.js:242-253) A Playwright dblclick finished in 48 ms, the page showed "LightDesk is closed. The stage is dark." and the dry-run server process exited. Close sits 10 px right of #boBtn (Blackout ends x 1460, Close starts x 1470). The armed label "Tap again to close" is 91 px of text inside a 57.7 px button. Move Close into the Desk menu, and in twoTap ignore a confirming tap that arrives less than 600 ms after arming. S1
P0-2 Screen 1 and screen 2 document keydown, desk.js:766-771, screen2.js:1062-1068 With VERSE live: open Desk menu, Esc closes it, a second Esc took live[] from [VERSE] to [] and undo depth from 1 to 0. Esc is the universal "get out" key, so a double press to dismiss a popover drops the running look. Esc only closes things; bind Undo to its own key (U) on both screens and update the Undo Esc hints. S1, S2
P0-3 Screen 2 screen2.js:1060-1075, no blackout element Screen 2 has no blackout control and binds only Esc, S, [, ], /, F1 to F4. After any click on screen 2 the keyboard belongs to that window, so the "hold B" printed on screen 1 does nothing and neither do the 24 hit keys or C. Bind B (700 ms hold, same as screen 1), C and the hit keys on screen 2 by calling the same desk API, and add a hold-to-blackout button in the On stage card. S2
P0-4 Phone #topBlackout, #undoBtn, #closeBtn in index.html:706-709 After scrolling 1200 px, Blackout and Undo sit at top -1192 px (off screen). Page height 2539 px at 390x844 (3.0 screens) and 2498 px at 844x390 (6.4 screens), plus 117 px horizontal overflow in landscape (body.v3 scrollWidth 961 vs 844). Blackout fires on a single tap (index.html:1464) while screen 1 needs a 700 ms hold. Close is 8 px from Blackout. phone.html keeps Blackout (700 ms hold) and Undo in a fixed bottom bar on every tab, leaves Close off the phone, and fits each tab without page scroll at both sizes. S3
P0-5 Screen 2 on the PC window placement pc-wave0-screen2.png: the Windows taskbar covers rows 1032 to 1080 (48 px, pixel probe at x 300 and x 1500). Screen 2's Undo button lives at y 1017 to 1061, so its lower 29 px are under the taskbar, and the sixth tile row is cut. An Explorer window also sat over the wall. Launch screen 2 true full screen (kiosk or F11 equivalent) from two-screen.ps1 and prove it with a PC screenshot whose bottom 48 px are LightDesk. D

P1

# Page Selector Measured Fix in one sentence Owner
P1-1 Screen 1 #moodWall .ldw-grid In "All", 14 of 83 mood tiles are visible; the other 69 sit in a horizontal scroller 5623 px wide inside a 934 px box with scrollbar-width:none, so nothing shows they exist. Family filters work (Electric shows all 12). Show "14 of 83" plus 44 px page arrows on the strip, or open on the running look's family instead of All. S1
P1-2 Screen 1 map and legend tokens.css --ld-k-spot, --ld-k-par, --ld-k-strip --ld-k-spot #62acff equals --ld-sel #62acff; --ld-k-par #f0a53a equals --ld-held #f0a53a; --ld-k-strip #8dff8d is green next to --ld-live #4ed48f. At idle the map draws 12 par icons in HELD amber and the strip in LIVE green. Move the kind hues off the five state hues (tokens.css says hue in the chrome means state only). S1
P1-3 Screen 1 and screen 2 tiles and chips --fam on .ldw-tile, #fams, .s2-famtag (accents from /api/scenes) Family accents: Band #ff4d5a (KILL is #ff5d55), Intimate #f2a65a and Signature #ffb347 (HELD is #f0a53a), Broadcast #38bdf8 and Club #00e5ff (SELECTED is #62acff). These draw the 4 px tile edges and chip borders on both screens, beside the green LIVE ring. Draw family as a neutral text tag and keep colour only in the look's own colour chips; or remap the 11 accents to hues outside the state set. S1, S2
P1-4 Screen 2 .s2-stage .bar i, screen2.css:209 With "IDLE, Nothing recalled yet" the bar renders full width in LIVE green because the default is transform:scaleX(1). Default the bar to scaleX(0) and fill it only while a look is live or fading. S2
P1-5 Screen 2, nothing picked .s2-groups > button.s2-group Six cards of 307.7x314 px each (28.0 % of the 1920x1080 screen) carry one icon and two lines. There is no way to pick a single light from screen 2 in this state. Replace with a "Rig now" board: one row per group, one 44 px cell per light showing its live colour and level from /api/rig/state, row label picks the group, cell picks the light. S2
P1-6 Screen 2 plan conflict .ldw-scroll The wall scroller is 492 px tall with an 83 px row pitch, so 6 rows of 11 = 66 whole tiles. A 96 px Playing rail inside the wall leaves 4 whole rows = 44 tiles, short of the plan's 60. Put the Playing rail in the top band (the inspector or Rig-now area, 0 to 452 px), never above the wall. S2
P1-7 Screen 2 plan conflict screen2.js:621 vs inspector.js:225 Screen 2 renders its own inspector (screen2.js:621 renderInspector). inspector.js renderInspector is mounted only by v2/demo.html and still contains the circular hue wheel (inspector.js:59, atan2 at :365) and the circular gobo ring (inspector.js:71-77, :382). Wave 3 lane T3 is told to build the Effect card in v2/inspector.js, where screen 2 will never show it. Build the Effect card in screen 2's inspector and delete the unused circular render path from inspector.js so nobody revives it. S2
P1-8 Screen 1 .fd .ld-btn.mute (11), .pad kbd (24), .u1 kbd, #boHelp kbd, #clearBtn kbd, #plan .zone, #readback Text at 10 to 10.5 px: Mute 10.5, hit key hints 10, Esc and B hints 10.5, Back wall and Audience 10.5. Another 38 labels at 11 px, including the three header pills and the nine stage marks. Floor all operator text at 12 px (--ld-fs-xs) and the Mute label at 13 px. S1
P1-9 Screen 2 .s2-famtag (10 px), gobo slot numbers em (10 px, 13), .s2-pad .tip (10 px), slot captions "Open" (10 px, 26) Smallest operator text on screen 2 is 10 px. Same 12 px floor. S2
P1-10 Phone #lmFx > button.fx.k-bar, .k-blind, .k-strip 10 targets under 44 px at 390x844: six bars 36x13, three blinders 30x18, strip 123.1x13. At 844x390: bars 64x19, blinders 50x29, strip 286.5x19. phone.html picks lights by group buttons and 44 px light cells, not by the scaled map glyphs. S3
P1-11 All three tempo No tap tempo, BPM or beat readout on screen 1, screen 2 or the phone; the old TAP stays hidden in index.html:734-747. Click depth to tempo: not reachable. Ships with the S1 tempo strip (key T) and the S3 phone tempo tap, as planned. S1, S3

P2

# Page Selector Measured Fix in one sentence Owner
P2-1 Screen 2 .s2-save .lds-view .rec::before, screen2.css:193 Camera tag "Live 2 fps" uses a KILL red dot. Use a neutral dot; red stays for blackout. S2
P2-2 Screen 2 .s2-dmx .c.hot, screen2.css:177-179 Changed DMX channels turn LIVE green. Use ink or a neutral underline for "changed". S2
P2-3 Screen 2 .s2-go, screen2.css:295, and .s2-prog i, :258 "Room is empty, start" and the photo sweep progress are HELD amber. Neutral ink button and neutral bar; amber only for held. S2
P2-4 Screen 2 .ldi-seg button.kill, inspector.js:110 and screen 2 shutter A selected Strobe, Pulse or Random mode paints HELD amber. Selected mode uses the standard pressed ink style. S2
P2-5 Screen 1 .keepmark, desk.css:105-106, .fd.keyfd.over, :107-109 The KEY floor mark (dashed, labelled 5) and KEY above floor use HELD amber. Draw the cap mark in ink or neutral; the planned inhibit cap mark should use the same neutral style. S1
P2-6 Screen 1 .fd .mute[aria-pressed=true], desk.css:98 A pressed Mute is HELD amber. Decide Mute's state colour once (held is defensible) and use it on the phone too. S1
P2-7 Screen 1 .bo .arc, desk.html and .ldc-hold svg, controls.js:43-45 The blackout hold progress is a 34 px circular arc. Replace with a linear fill across the button, per Greg's linear rule. S1
P2-8 Screen 1 and screen 2 key hints Bound but not shown: S (save) on screen 1, [ and ] (only in the #fadeSeg title tooltip), F1 to F4 tabs on screen 2. Print the keys on the controls they drive. S1, S2
P2-9 Screen 2 .ldw-tile.has-none Tiles without a photo overflow: content 152 to 169 px wide in 136.8 px tiles, so "NO PHOTO YET" prints over SILHOUETTE, BLUE LIGHTNING and others. The PC has mood photos, so this shows on new scenes and beams without one. Replace the three-word text with the camera glyph alone, or put it on its own line. S2
P2-10 Screen 2, pars picked Gobo, Position, Beam cards Three cards, 492 + 386 + 308 px wide by 312 px tall, each holding one 34 px sentence ("No gobo wheel on a led par"). Collapse non-applicable cards to one 44 px line and give the width to per-light level faders. S2
P2-11 Screen 2, spot picked .s2-read Pan and Tilt read "?" when the position is not known. Print "not known yet". S2
P2-12 Cross-page status and undo Screen 1 header reads "Live room" next to "Preview, lights muted". Screen 2 shows no output state at all. The phone shows preview in HELD amber and the active filter chip in SELECTED blue, while screen 1 uses neutral grey and ink. Undo sits top right on screen 1 (x 1150, 150x44), bottom left on screen 2 (x 21 y 1017, 294x44), in the top bar on the phone (x 117, 80.2x44). One output pill (neutral when preview, green only when driving lights) on all three, and the same pressed style for filters. S1, S2, S3
P2-13 Screen 1 .pad.pk with nothing picked With Plays on: Picked and nothing picked, the six pick-light pads render dimmed with no reason given. Show "pick lights first" on the pads, or fall back to Usual. S1

Click depth per operator action

Action Screen 1 Screen 2 Phone (index.html)
Pick one light 1 tap on the map 2 taps (group card, then a head chip) map glyphs, 10 of them under 44 px
Pick a group 1 tap (Spots, Washes and the rest) 1 tap on a group card map
Clear 1 tap or C none none
Point 1 tap on a mark after the pick 1 tap on a mark (spot or wash picked) tap the picture
Mood 1 tap for 14 of 83; 2 taps (family, tile) for the rest 1 tap for 66 of 83 at M 1 tap after scrolling
Hit hold or key, 24 pads, 24 keys none after scrolling
Blackout hold 700 ms or hold B none, no key single tap, scrolls away
Undo 1 tap or Esc 1 tap or Esc 1 tap, scrolls away
Save scene S key only, no control 1 tap or S none
Fade 1 tap or [ ] 1 tap or [ ] not measured
Tempo none none hidden

Proposed screen 2 empty state, P1-5 in full

"Rig now", 1920 x 452 px, replacing the six group cards: - One row per group (Spots, Washes, Pars, Bars, Blinders, Profiles), 64 px tall, label on the left as a 44 px button that picks the group. - One 56 x 44 px cell per light in map order, filled with the light's live colour and a linear level bar along its bottom edge, from /api/rig/state (level, rgb). - Tap a cell to pick that light alone, which opens the inspector in the same band. - Lit-light count and the running look's name on the right of each row. - This doubles as the Playing rail's home (P1-6), and gives screen 2 the single-light pick it lacks today.

Evidence

Headless renders and per-view measurement JSON were written to the session scratch folder /private/tmp/claude-501/-Users-gregspero/2adb11bf-8bde-4fe9-b6b3-a89087aa432b/scratchpad/out/ (s1, s1-spot, s1-live, s1-dark, s2-empty, s2-spot, s2-pars, s2-live, ph-p, ph-l, ph-390-scrolled, ph-844-scrolled). That folder is temporary; lane D's capture harness should regenerate shots at wave 2 head.