rtmg/web: named-slot prompt deck (kill A/B crossfade)#178
Conversation
There was a problem hiding this comment.
The deck UI itself is genuinely great. The named-slot framing, the bay integration, and the Strength/Structure hint are all real wins.
My one hard blocker is that this removes controllable prompt blending as a capability.
It comes down to the philosophy we talked through yesterday: DEMON is an instrument, and for an instrument the answer is always more control, never less. People perform on MIDI controllers, and blending between two prompts on a knob is an obvious, expressive gesture. That's not an edge case, it's an example of the core that makes this an instrument.
The PR's reasoning is basically "users read the slider as an abstract implementation detail." Fair observation, but that's a communication problem, not a feature problem, and with a handful of user interviews behind it I don't think we have the signal to call it. Before removing something hard-won with explicit use cases because people don't immediately get it, I'd want to ask:
- Is there a better way to present the gesture so it reads as musical? (e.g. blend lives on the slots: hold/drag between two chips, not a naked A/B slider.)
- Who's actually confused, and how many? Excising a practical, hard-won feature is a high bar: I'd want a large sample and a supermajority before I'd believe removal beats redesign.
And these two behaviors aren't in tension. A clean tap-to-switch deck and controllable blend (drag/hold between slots) can live in the same design: the deck is the simple default, the blend is the depth underneath. The shift-click / two-finger live-blend you already noted as a follow-up is exactly the right seed.
So my ask: keep this PR's UI wins, but treat the simplification as configurable depth, not removal. Simplify the default surface; keep the full blend control reachable. If we simplify, it should be opt-in, not destructive.
Requesting changes on that basis, but I'm excited about where this goes. Happy to whiteboard the combined version anytime.
The more knobs we add, the more this becomes an instrument, which is what differentiates this from other AI music tools.
|
Super valid @ryanontheinside! I’ll do another round with controllable blending restored. |
4733b7f to
730cd9e
Compare
|
crossfader is back with MORE CONTROLLABILITY THAN BEFORE. Both endpoints are popover-pickable, so you can use any pair (A→B, A→C, B→C, etc). |
The old A/B textareas + crossfade slider tested badly: operators read
the blend slider as a confusing implementation detail and the deck was
buried two levels deep in the drawer. Three changes here:
1. Prompt deck. PromptsTile now shows ONE active textarea and a strip
of named slots ("+", rename, delete). Tapping a slot ping-pongs the
new prompt through the engine's inactive A/B slot and tweens
prompt_blend toward it via the existing smoothing system — the lerp
is preserved, just no longer operator-visible. Slot list is client-
only (lib/promptDeck.ts orchestrates); server protocol unchanged.
2. Strength/Structure hint. Inline caption under the textarea:
"Hits hardest at high Strength + low Structure." The relationship
was tribal knowledge; this surfaces it where operators actually
read it.
3. HeroMacros gets a Prompts zone — compact slot chips + a "⋯" that
opens Full Controls already routed to the Styles tab via a new
dd:open-drawer-tab event. To free horizontal room without
eating Tools, the Record / Curve / Full / MIDI buttons are now a
2x2 grid instead of a vertical 4-stack.
Defaults seed two slots (Dubstep, Daft Punk) from the existing
promptA/promptB defaults so the deck is non-empty from the first
session. Saved-session restore still writes promptA/promptB directly
and the deck rebuilds on next interaction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-2 iteration on the prompt-deck UX after dogfooding the first pass. Three changes: 1. Hero-bay reverted to original 4-tool vertical stack. The 2x2 grid + PromptDeckChip from the previous commit are out — putting a slot-deck chip in HeroMacros felt cluttered, and turning Tools into a grid miscategorized "Prompt Mode" as a peer of Record / Curve / MIDI. The deck UX in PromptsTile (drawer Styles tab) stays as-is. 2. New "Prompt Mode" bay view — focused surface for tuning the active prompt. Layout: Strength + Structure knobs | prompt textarea + Send | Emphasize prompt / Disable lora auto-trigger / Full Controls. Mode toggle is a floating Dock/Prompt segmented control above the bay's top edge — sits in bay chrome, not in the tools cluster, so it reads as a view switcher rather than an action tool. Same position in both modes. Auto-snaps back to Dock when the drawer or curve overlay opens. 3. "Disable lora auto-trigger" checkbox (per-session, default off) gates both enabledLoraTriggerPrefix() and stripLeadingTriggers() at call time, so when on, the wire prompt is exactly the operator's text — no prepend, no strip. Applies to every send path (Send button, in-tile Send Tags, MCP-driven sends, key/sig re-sends) because the gate lives in the helpers themselves. "Emphasize prompt" checkbox caches the current hint_strength target, snaps to 0.15 while on, restores the cached value on toggle-off or view exit (component unmount). Toggling Structure manually while emphasize is on still works — the restore goes back to the pre-emphasize value, not the post-touch one, so the toggle remains a clean undo. Drops the dd:open-drawer-tab event + AdvancedDrawer handler — only consumer was the removed chip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses Ryan's PR-178 feedback: prompt blending should be a
first-class instrument gesture, not an opt-in. Round-3 rebuild of
the prompt deck UX:
1. Always-on crossfader in PromptsTile when slots.length >= 2.
Generalizes the legacy A/B blender to any pair: both endpoints
are popover-pickable, so A→B / A→C / B→C are all expressible by
re-pointing either side. data-param="prompt_blend" carries
through so right-click → MIDI-learn binds to a hardware knob
exactly like before, and the "B + ▲▼" keyboard nudge is still
wired (kbd hint restored).
2. Three concerns kept deliberately separate in the perf store:
- focusedSlotId → textarea binding (UI-only)
- currentSlotId → engine A endpoint
- blendPartnerId → engine B endpoint
Tap a chip = focuses it (★ badge); A and B don't move. The
crossfader's labels stay stable mid-performance — they only
change when the operator explicitly picks via the A or B
popover. Editing the focused chip's text mirrors to engine
promptA/promptB only when that chip is also loaded; otherwise
edits stay in the slot until the operator loads it.
3. Endpoint badges (A / B) on the deck chips show "where is X
loaded?" at a glance. Removed the dedicated "↹ Blend with…"
button + the ✕ clear button — both rendered moot by the
always-on crossfader with clickable endpoints.
4. lib/promptDeck.ts is now a thin orchestration layer:
- focusPromptSlot(id) → pure UI focus shift
- setBlendEndpointA(id) → load to engine A (+ focus)
- setBlendPartner(id) → load to engine B (+ focus)
- addAndFocusPromptSlot() → add + focus, no auto-load
- removePromptSlot(id) → re-pick endpoints / focus
ensureValidPartner() runs after every mutation so the
crossfader always has a valid non-self partner whenever there
are 2+ slots — and clears to null (slider hidden) at 1 slot.
Hero Prompt Mode is unchanged — it binds to currentSlotId
(engine A, what's playing) which is the right semantic for the
performance surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
730cd9e to
35dbcf4
Compare
Summary
Three coordinated UX changes to the Tags feature in the realtime motion-graph web demo.
1. Kill the A/B crossfade. Replace with a named-slot deck.
The old two-textarea + blend-slider UI read as an abstract implementation detail. Operators rarely manually scrubbed the slider mid-performance; the more common gesture was "I want to switch to a different idea." So:
2. Surface the Strength/Structure dependency.
Inline caption under the textarea: "Hits hardest at high Strength + low Structure." The relationship was tribal knowledge that the UI never communicated.
3. HeroMacros gets a Prompts zone.
Compact slot-chip strip in the bottom-center bay (mirrors the Styles fader zone next to it) + a `⋯` that opens Full Controls already routed to the Styles tab — new `dd:open-drawer-tab` event lets the chip address "open drawer + select tab" in one move. To make horizontal room without compressing Tools, the Record / Curve / Full / MIDI buttons are now a 2×2 grid instead of a vertical 4-stack.
State model
New store fields on `usePerformanceStore`:
Switching: load target into the inactive engine slot, `sendPrompt(A, B)`, set `prompt_blend` target to the inactive slot, swap `physicalSlot`. The Smooth toggle's `smoothMs` controls the transition duration; with smoothing off the switch is instant.
Defaults seed two slots from the existing promptA/promptB defaults so the deck is non-empty from the first session. Saved-session restore continues to write `promptA/promptB` directly; the deck rebuilds on next interaction.
Test plan
Follow-ups (out of scope for this PR)
🤖 Generated with Claude Code