Skip to content

fix(studio): use e.key for playback shortcuts so non-QWERTY layouts work#839

Merged
jrusso1020 merged 1 commit into
heygen-com:mainfrom
calcarazgre646:fix/studio-playback-shortcuts-keyboard-layout
May 14, 2026
Merged

fix(studio): use e.key for playback shortcuts so non-QWERTY layouts work#839
jrusso1020 merged 1 commit into
heygen-com:mainfrom
calcarazgre646:fix/studio-playback-shortcuts-keyboard-layout

Conversation

@calcarazgre646
Copy link
Copy Markdown
Contributor

What

The 7 letter shortcuts (J/K/L/I/O/A/E) in packages/studio/src/player/hooks/usePlaybackKeyboard.ts are gated on e.code === "Key*", which is the physical key position on a US-QWERTY layout. On AZERTY (and other layouts) the physical KeyA slot produces e.key="q", so "Jump to in-point" and the rest of the letter shortcuts either fire on the wrong character or not at all.

Switch the 7 letter shortcuts to compare e.key.toLowerCase() and rename pressedCodesRefpressedKeysRef so the K-hold combo (K+J / K+L for frame stepping) is also keyed off the typed character. Space and Arrow* keep e.code since those codes are layout-independent.

Scope

Addresses bug #3 in #834 (the AZERTY one originally reported for A, generalized here to all 7 letter shortcuts since the same e.code pattern was used in 7 places).

Bug #1 (loop at out-point) and bug #2 (Jump to in-point forcing pause) from the same issue are left for follow-up PRs — they live outside this hook (player loop and adapter seek respectively) and a focused PR is easier to review.

Tests

New usePlaybackKeyboard.test.ts (happy-dom) covering:

  • QWERTY: physical KeyA + e.key="a" → seek to in-point fires
  • AZERTY: physical KeyQ + e.key="a" → seek to in-point fires
  • AZERTY contrapositive: physical KeyA + e.key="q" → seek does not fire
  • Shift+I clears in-point (e.key="I" is matched after lowercasing)
  • K-hold + L → single frame step (combo uses character, not physical position)
  • K released → subsequent L resumes forward shuttle
  • Space passthrough (e.code path still works)

Out of scope (intentionally)

  • Non-Latin layouts (Cyrillic, Arabic, etc.) — e.key is the localized character there, which won't match ASCII shortcut letters. This matches the convention in Google Docs / VS Code and the issue did not request it.

Validation

  • bunx oxlint <changed> → 0 warnings, 0 errors
  • bunx oxfmt --check <changed> → clean
  • bun run --cwd packages/studio typecheck → clean
  • bun run --cwd packages/studio test → 497 passed (47 files), including the 7 new tests

The 7 letter shortcuts (J/K/L/I/O/A/E) in usePlaybackKeyboard were gated
on `e.code === "Key*"`, which is the physical key position on a US-QWERTY
layout. On AZERTY (and other layouts) the physical "KeyA" slot produces
e.key="q", so "Jump to in-point" and the rest of the letter shortcuts
either fired on the wrong character or not at all.

Switch the 7 letter shortcuts to compare `e.key.toLowerCase()` and rename
`pressedCodesRef` → `pressedKeysRef` so the K-hold combo (K+J / K+L for
frame stepping) is also keyed off the typed character. `Space` and
`Arrow*` keep using `e.code` since those codes are layout-independent.

Adds a happy-dom test covering QWERTY happy path, AZERTY (physical KeyQ
produces e.key="a" → in-point seek fires), AZERTY contrapositive (physical
KeyA producing e.key="q" no longer triggers in-point), Shift+I clears
in-point, K-hold combo for frame stepping, K release returning the set
to clean state, and Space passthrough.

Addresses bug heygen-com#3 in heygen-com#834. Bugs heygen-com#1 (loop at out-point) and heygen-com#2 (Jump to
in-point forcing pause) live outside this hook (player loop and adapter
`seek` respectively) and are left for follow-up PRs.
@jrusso1020 jrusso1020 merged commit 4177c32 into heygen-com:main May 14, 2026
24 checks passed
jrusso1020 added a commit that referenced this pull request May 14, 2026
…o legible

Two surgical changes, both isolated to the catalog-previews flow:

1. `packages/studio/src/player/hooks/usePlaybackKeyboard.test.ts`
   PR #842 changed `seek()` to take `(time, { keepPlaying: true })` for the
   A/E shortcuts. The keyboard-layout tests added by #839 still asserted the
   single-arg form. Both landed on main without cross-checking, so `main`
   itself has been failing Test/Windows since. Update the two assertions
   to match the new signature. Same fix Miguel already authored on
   `feat/studio-preview-pasteboard-bg`.

2. `registry/components/vignette/demo.html`
   The original demo captured a frame where the vignette was at its
   weakest point — the effect was nearly invisible in the static preview
   used by docs. Reworked the demo so:
   - The backdrop is a layered "cinematic still" (warm key + teal rim +
     dark falloff) and includes a centered subject ("moon"), so the
     vignette has a focal point to frame.
   - Vignette starts soft (size 70%, alpha 0.35) and ramps to a dramatic
     cinematic vignette (size 26%, alpha 0.92) over 1.6s.
   - Peak intensity holds across t≈3.0s, which is exactly where the
     catalog script samples the thumbnail (`Math.min(3.0, duration*0.6)`
     with duration=5).
   - Breathing motion in t=3.4–5.2s gives the video loop visible life
     without disturbing the still frame.
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.

3 participants