Skip to content

Fix generate-shortcut papercuts across Studio, Canvas, and Compare - #1

Open
usehoplite[bot] wants to merge 4 commits into
mainfrom
hoplite/hermion-53ea6b40
Open

Fix generate-shortcut papercuts across Studio, Canvas, and Compare#1
usehoplite[bot] wants to merge 4 commits into
mainfrom
hoplite/hermion-53ea6b40

Conversation

@usehoplite

@usehoplite usehoplite Bot commented Sep 2, 2026

Copy link
Copy Markdown

Summary

Audited the main user flows (Studio prompt → generate, Compare models, AI Canvas nodes) for common UX papercuts. All three surfaces advertised a ⌘/Ctrl+Enter generate shortcut that was broken or misleading:

  1. Studio Generate — the button showed a hardcoded macOS hint (⌘↵) on every platform, and the shortcut only worked while focus was inside the prompt textarea. Pressing ⌘/Ctrl+Enter with focus anywhere else did nothing.
  2. Canvas prompt/video nodes — keystroke handling skipped all typing targets, so ⌘/Ctrl+Enter inside a node's editor (the advertised "generate selected" binding) was swallowed; users hit a dead end exactly where the shortcut is most expected.
  3. Compare modal — same hardcoded macOS hint, and the shortcut only fired from the modal's prompt textarea.

Changes

  • src/components/PromptPanel.tsx — window-level ⌘/Ctrl+Enter handler that triggers the same generate() as the button, guarded so it never fires behind an open modal or a pending batch; hint rendered per-OS via the existing formatKeyCombo helper.
  • src/features/ai-canvas/components/useCanvasKeybinds.ts + PromptNode.tsx / VideoPromptNode.tsx — while typing in a node editor, ⌘/Ctrl+Enter runs that node (prompt or video), mirroring the node's own Generate button. Node articles now carry data-node-id so the handler resolves the owning node without relying on React Flow internals.
  • src/components/CompareModal.tsx — comparison shortcut moved to a window-level handler (works from anywhere in the modal, not just the textarea); hint per-OS.
  • .hoplite/settings.json — managed-preview config so a fresh sandbox gets a working app: Vite on 4000 plus the API server on its default 4001 (the injected preview PORT previously collided both onto 4000, breaking /api proxying). Setup also installs git-lfs, which the source-control flow requires.

Verification

bun run check — 64 tests pass, tsc -b && vite build clean.

Behavioral evidence (headless Chrome against the dev stack, API intentionally keyless):

Surface Before After
Studio, focus outside textarea Ctrl+Enter → no request (verified via fetch interception) Ctrl+Enter → exactly one POST /api/generate; failure surfaces in the existing error banner
Studio, focus in textarea exactly one request still exactly one request (no double-fire after moving the handler)
Canvas node editor Ctrl+Enter → nothing Ctrl+Enter → runs the focused node (node entered running → failed state with provider error)
Compare modal, focus outside textarea nothing Ctrl+Enter → comparison runs both slots (button transitions Run Compare → Re-run)

Hint labels on Linux now read Ctrl+Enter instead of the hardcoded ⌘↵; macOS renders ⌘↵ as before.

Studio generate button with platform-correct hint

Compare modal with shortcut hint and results

Screenshots are post-fix evidence of the hint labels; the interaction claims above were verified non-visually (network interception, DOM state transitions). No pixel-level visual verification was performed.

Open in Hoplite

Note

Fix Meta/Ctrl+Enter generate shortcuts across Studio, Canvas, and Compare

  • Moves the Studio prompt generation shortcut to a window listener in PromptPanel.tsx that checks for generating state, modals, and the new activeOverlay flag before running.
  • Updates CompareModal.tsx to handle Meta/Ctrl+Enter via a window listener and refactors its UI into dedicated subcomponents.
  • Updates useCanvasKeybinds.ts so Meta/Ctrl+Enter inside a canvas node runs that node instead of inserting a newline, using data-node-id for lookup.
  • Adds the activeOverlay state to the Studio store, managed by LibraryModal.tsx to block shortcut conflicts.
  • Behavioral Change: Canvas text inputs now run their node on Meta/Ctrl+Enter instead of inserting a newline; the Studio prompt shortcut is suppressed when activeOverlay is true or modals are open.

Macroscope summarized 2a210de.

usehoplite Bot and others added 2 commits September 2, 2026 03:15
The API server and Vite dev server previously collided on the injected
preview PORT, and no run script was configured. Pin the API server to its
default 4001 and start both servers so a fresh sandbox gets a working app.

Co-authored-by: Kactus <thekactusapp@gmail.com>
The Studio and Compare-model buttons showed a platform-wrong, hardcoded
macOS hint (⌘↵) and only handled the shortcut while focus sat in their
prompt textareas. The canvas node editors swallowed ⌘/Ctrl+Enter entirely
because the keybind handler skipped typing targets.

- Studio: window-level ⌘/Ctrl+Enter triggers Generate from anywhere,
  unless a modal is open; hint renders per-OS (⌘↵ / Ctrl+Enter).
- Canvas: editing a prompt or video node and pressing ⌘/Ctrl+Enter
  runs that node, matching the binding advertised in the keybinds panel.
- Compare modal: the same shortcut now runs the comparison from anywhere
  in the modal and the hint is platform-correct.

Co-authored-by: Kactus <thekactusapp@gmail.com>
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 2a210de.

Comment thread src/components/PromptPanel.tsx
if (!nodeId) return
const node = useAICanvasStore.getState().nodes.find((entry) => entry.id === nodeId)
if (!node) return
const runnable = (isPromptNode(node)

@macroscopeapp macroscopeapp Bot Sep 2, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium components/useCanvasKeybinds.ts:39

⌘/Ctrl+Enter invokes generation for prompt nodes whose customProviderId no longer resolves, and for video nodes whose ID is missing or does not identify a video provider, even though the visible Generate button is disabled; the action then puts the node into an error state. The typing shortcut's runnable checks must use the same resolved-provider and endpoint validation as the Generate button instead of only checking prompt text and a nonempty ID.

✅ Resolved in b1c581c

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b1c581c: the typing shortcut now uses a shared canGenerateNode check that mirrors the Generate-button enablement exactly — prompt nodes with provider === 'custom' require a resolved custom provider with a non-video endpoint, and video nodes require a resolved provider with endpointMode === 'video'. The same helper also backs the selected-nodes ⌘/Ctrl+Enter path, which had the same weak check.

- Studio: stop the shortcut from firing when another listener already
  claimed the keystroke (event.defaultPrevented).
- Canvas: the ⌘/Ctrl+Enter runnable check now mirrors the Generate-button
  enablement exactly — custom providers must resolve to an image or video
  endpoint — so the shortcut can't run a node whose button is disabled.
- Compare modal: split the oversized component into TopBar, PromptBar,
  Slots, Results, and EmptyState sections (react-doctor no-giant-component).

Co-authored-by: Kactus <thekactusapp@gmail.com>
@usehoplite

usehoplite Bot commented Sep 2, 2026

Copy link
Copy Markdown
Author

The no-giant-component warning is addressed in b1c581c: CompareModal was split into CompareTopBar, ComparePromptBar, CompareSlotsSection, CompareResultsSection, and CompareEmptyState. A local react-doctor run against src/ confirms CompareModal.tsx no longer appears under no-giant-component (only pre-existing, untouched components remain). The modal's behavior was re-verified in the browser — slot config, ⌘/Ctrl+Enter run, and per-slot result cards all render as before.

Comment thread src/components/PromptPanel.tsx
LibraryModal is owned outside PromptPanel, so its open state was invisible
to the Studio shortcut guard and Ctrl/⌘+Enter started a generation behind
the modal. Track a shared activeOverlay flag in the studio store: the
Library modal registers itself while mounted, and the global generate
shortcut bails out whenever an overlay is active.

Co-authored-by: Kactus <thekactusapp@gmail.com>
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.

0 participants