Skip to content

feat: lay the input controls over the wall and rebuild Settings - #334

Merged
BernardJen merged 6 commits into
mainfrom
feat/dropdown-over-the-wall
Oct 3, 2026
Merged

BernardJen merged 6 commits into
mainfrom
feat/dropdown-over-the-wall

Conversation

@BernardJen

@BernardJen BernardJen commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Implements the Claude Design handoff HANDOFF-2b.md: dropdown 2b "Over the wall" and the new Settings (1e). Behaviour follows the functional spec for v3.3.4 (2e26017).

Dual view with the input controls open

Dropdown 2b

  • There's no panel any more. Opening it (hover or tap the top tab) lays a picker over each half: the current input, a strip of 128×72 snapshot tiles, and that half's volume. A capsule at the top holds Dual/Single, Output and Settings, and a 56px Close pill sits at the bottom.
  • Number-key chips appear only where a tap does what the key does: in single view, and in dual view without Multi-view.
  • The pickers re-render after number keys, renames, enable/disable and hot-plug, not only after clicks. The cursor stays visible while they are open.

Multi-view (multiView, default true)

  • Off: dual view always shows the same input on both halves, with one "Both halves" strip and one volume slider that sets both sides.
  • It is in the save allowlist and in main's defaultSettings. Turning it off brings the right half in line with the left, and startup enforces the same.

Settings

  • A 920×680 modal with a side nav: Inputs, Layout, Remote keyboard, Art-Net lighting. Each nav item shows a status. The footer moved into the nav.
  • Removed: the shortcut table (the legend has the same rows) and the No-Signal Detection section.
  • Inputs:
    • Multi-view switch.
    • The orphaned-reference banner has correct grammar and the "only unplugged" caveat.
    • Columns are Key / On / Name / Startup / No-signal.
    • The Name field shows the hardware label as its placeholder. The Startup pill can be cleared.
    • The No-signal panel has "Capture from left/right half". It is disabled with "Put this input on the wall first" when the input isn't showing, and it shows an inline message when a capture fails.
    • An input switched off while on screen shows "Still on the wall until you switch".
  • Layout: a to-scale drawing of the 5:1 wall above the two sliders.
  • Remote keyboard: API key Show/Hide, and a status line built from the result of the last press.
  • Art-Net: a status line driven by the previously unused getStatus(), a count of customised screensavers, and a two-column grid of per-screensaver modes.

Fixes

  • Remote keyboard never added .local to a bare hostname (http:// was prepended first). The URL logic is now in settings-status.js and unit tested.
  • Remote keyboard presses go through the main process (remote-key-send), for the same CORS reason Art-Net does.
  • Shortcuts now ignore every form control. With a <select> focused, Q used to quit the app. Escape still gets through.
  • Esc does one thing per press: with a panel open it closes the panel and stops there, without leaving fullscreen.
  • textContent is used instead of innerHTML for names in Settings and the volume rows.
  • The input-name toast timer is now cleared, and the toast is suppressed while the pickers are open.
  • The presenter debug overlay is hidden while Remote Keyboard is off.
  • The Art-Net scene catalogue is fetched debounced instead of once per keystroke.

After review in the dev instance

  • The shortcut drop-up is restyled with the same surface, corners, mono title and key chips. It fades instead of sliding, and its tab gets keyboard and ARIA handling.
  • Range sliders fill blue up to the thumb. This is done with a --fill CSS variable set by paintRangeFill().
  • The settings icon is a real gear. The placeholder looked like a sun.
  • The volume sliders have a speaker icon. It shows a mute cross at 0, then one, two or three waves as the volume rises. The waves draw in with a stagger.
  • The Close pill is removed. The controls now close when the pointer goes more than 48px below the lowest picker row, which is the volume slider. On touch, tapping that area closes them. Esc and the 30 s idle close are unchanged.

Where this differs from the handoff

  • System fonts only. TT Interphases is licensed for internal SBP use, and this repo and its installers are public.
  • Icons are placeholders. They are simple line SVGs until the design file and settings-gear.svg are exported. The square corner of the containers (--radius-container) is a guess.
  • Auto-close after 30 s idle. This is not in the handoff. The controls cover the wall and don't close when the pointer leaves, so without it they could stay over an unattended wall.
  • Changed reference hint text. It said "use Capture above"; it now says "capture it below", because the button moved.
  • Settings path removed from the README. The README said the Settings panel shows the settings file path; it never did.

For design review

At 6000×1200 everything is the handoff's size (128×72 tiles, 22px names), but it fills only the top-left of each ~3000px half. It probably wants scaling on the wall.

Testing

  • npm run lint passes, and npm test passes 933 tests, 47 of them new:
    • settings-status.test.js covers the pure status logic.
    • settings-panel.test.js runs against the real index.html, and checks that the page contains every id renderer.js looks up.
  • electron-vite build succeeds.
  • Checked by hand in --mock and --mock=8:
    • sizes: 1280×800 and 6000×1200
    • long names, Multi-view on and off, and all four Settings panes
  • Not done: a real capture card, the wall itself, and touch hardware.

🤖 Generated with Claude Code

BernardJen and others added 6 commits October 3, 2026 19:28
Implements the dropdown 2b ("Over the wall") and Settings handoff.

Dropdown: no panel any more. Opening it puts a picker over each half
(current input, a strip of 128x72 snapshot tiles, that half's volume),
a capsule at the top (Dual/Single, Output, Settings) and a Close pill
at the bottom. It closes with Close, Esc, or after 30s idle.

Multi-view (new `multiView` setting, default on): off makes dual view
show one input on both halves, with a single strip that sets both.

Settings: a 920x680 side-nav modal with Inputs, Layout, Remote keyboard
and Art-Net panes, each with a status in the nav. Capture moved into
each input's No-signal panel; the shortcut table and the separate
No-Signal Detection section are gone (the legend has the shortcuts).
Inputs gain a Key column, a hardware-label placeholder, a clearable
Startup pill and an inline capture result. Layout gets a to-scale wall
diagram. Remote keyboard and Art-Net get status lines; the API key a
Show/Hide toggle.

Fixes along the way:
- remote keyboard never added .local to a bare hostname
- remote keyboard presses now go through main (CORS from file://)
- shortcuts fired with a <select> focused (Q quit the app)
- one Esc closed Settings and left fullscreen
- names were interpolated into innerHTML in Settings and volume rows
- the orphaned-reference banner said "1 reference belong"
- the input-name toast timer was never cleared on rapid switching
- the presenter debug overlay outlived Remote Keyboard being turned off
- the Art-Net catalogue was fetched on every keystroke of the URL

System fonts only: the handoff's brand face is licensed for internal
use and this repo and its installers are public.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same surface, hairline and corner rule as the capsule and Settings, a
mono title, the new key chips, and a fade instead of a slide. It floats
just above the bottom edge, overlapping its tab so a hover can move from
the tab into the panel without crossing a gap. The tab gets the same
keyboard and ARIA handling as the top one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The custom track was one flat grey, so a slider's value only showed as
the thumb's position. The track is now a gradient that reads --fill,
which paintRangeFill() keeps in step on input and after any render
that sets a value programmatically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The placeholder was a circle with eight thin rays, which reads as a
sun. It is now an eight-tooth gear outline with a centre hole, until
the design's settings-gear.svg is exported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ets louder

Muted shows a cross; then one, two or three waves past each third.
A wave arriving draws itself in from the speaker outwards, staggered
so a jump from silent to loud ripples out; one leaving fades. On the
picker volumes and the Output slider, driven by paintRangeFill so it
follows the slider however its value changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the Close pill. Past the lowest picker row plus 48px, moving
the pointer closes the controls; the line is the volume slider rather
than the thumbnails, so reaching for the slider does not. On touch a tap
in the same area closes them. Esc and the 30s idle close are unchanged.
The legend tab is no longer hidden while the controls are open, since
the pill that sat on top of it is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BernardJen
BernardJen merged commit 80b88f1 into main Oct 3, 2026
1 check passed
@BernardJen
BernardJen deleted the feat/dropdown-over-the-wall branch October 3, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant