feat(editor): keystroke overlay — render layer + persistence (Part 2/3)#1
Merged
starkdcc merged 8 commits intoJul 11, 2026
Merged
Conversation
…layer (2/3) Builds on the capture + display foundation (webadderallorg#733): - projectPersistence + editorPreferences: persist showKeystrokes / keystrokePosition / keystrokeSize (mirrors the cursor prefs), normalized and defaulted (off / bottom-center / 1x). - PixiKeystrokeOverlay: a parent-agnostic PIXI layer mirroring PixiCursorOverlay's construct/update/reset/destroy contract, driven entirely by the tested coalescing core; pooled Graphics + Text keycaps, screen-anchored (bottom/top), size-scaled, with per-group fade. - detectGlyphStyle(): platform-aware modifier glyphs (guarded for Node tests). tsc clean (electron + renderer); 25 pure-core tests pass. Remaining wiring (settings-panel controls + parent threading, VideoPlayback instantiation, keystroke sidecar persistence + IPC, export parity) needs a local dev loop to verify and is tracked as the follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the main-process persistence layer for keystroke telemetry, mirroring the
cursor .cursor.json sidecar exactly:
- utils: getKeystrokePathForVideo -> `${videoPath}.keystrokes.json`
- telemetry: normalizeKeystrokeTelemetrySamples, writeKeystrokeTelemetry,
persistPendingKeystrokeTelemetry, snapshotKeystrokeTelemetryForPersistence
(use KEYSTROKE_TELEMETRY_VERSION / MAX_KEYSTROKE_SAMPLES; skip/remove the
sidecar when empty, matching the cursor path).
tsc (node) + biome clean. Wiring these into set-recording-state, the stop
paths, a get-keystroke-telemetry IPC channel, and the renderer load path is
the remaining follow-up (see PR description checklist).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e prefs Adding showKeystrokes/keystrokePosition/keystrokeSize to PersistedEditorControls left captureEditorPresetSnapshot's EditorPresetSnapshot literal missing them. Add the three fields (placeholder defaults until VideoEditor manages keystroke settings in part 3). Full-project tsc is now clean except one pre-existing unused import (VideoPlayback scalePreviewBorderRadius) that predates this branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- recording.ts: enable keystroke capture at record-start when showKeystrokes is set (new set-recording-state options arg); disable + snapshot on all stop paths (native-win + set-recording-state); add get-keystroke-telemetry read handler mirroring the cursor one. - preload + electron-env: getKeystrokeTelemetry bridge, setRecordingState options, KeystrokeTelemetryPoint type. tsc (node) clean. Renderer wiring (overlay mount + settings toggle) is the remaining follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…derer) Completes the keystroke overlay end to end: - VideoEditor: keystrokeTelemetry state + load effect (get-keystroke-telemetry), showKeystrokes/position/size state, props to VideoPlayback + SettingsPanel. - VideoPlayback: mount PixiKeystrokeOverlay in a sibling container, per-frame update (outside the cursor-overlay branch so it renders independently), plus attach/destroy lifecycle; drop a pre-existing unused import. - SettingsPanel: 'Show Keystrokes' toggle + size slider. - useScreenRecorder: pass showKeystrokes to setRecordingState at record start. - i18n (en): effects.showKeystrokes / effects.keystrokesSize. Full-project tsc clean (both configs); 25 keystroke tests pass; Electron dev build boots and renderer renders with zero console errors. Position Select and the other 9 locale strings are trivial follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ext recording Add showKeystrokes/keystrokePosition/keystrokeSize to the saveEditorPreferences bundle (+ effect deps). Without this, toggling 'Show Keystrokes' only affected the in-editor overlay; capture is gated at record-start on the persisted pref (loadEditorPreferences().showKeystrokes), so the toggle must persist to actually capture keystrokes on the next recording. Closes the end-to-end loop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move 'Show Keystrokes' out of the cramped 3-toggle header row into its own full-width labeled row at the top of the cursor panel body, with a full-size switch (was scale-75) so its on/off state is obvious. Header returns to Show Cursor + Loop cursor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Keystroke overlay — Part 2 of 3 (render layer + persistence)
Stacked on webadderallorg#733 (capture + display foundation). Based on the
feat/keystroke-overlay-foundationbranch so this diff shows only Part 2's changes — review webadderallorg#733 first.What's in this PR (all
tsc+ Biome clean; 25 pure-core tests pass)showKeystrokes/keystrokePosition/keystrokeSizeadded toProjectEditorState+editorPreferences, normalized and defaulted (off / bottom-center / 1×), mirroring the cursor prefs.PixiKeystrokeOverlay— a self-contained PIXI render layer mirroringPixiCursorOverlay'sconstruct/update/reset/destroycontract, driven entirely by the tested coalescing core. PooledGraphics+Textkeycaps, screen-anchored (bottom/top, L/C/R), size-scaled, per-group fade. Type-checked against PixiJS v8.detectGlyphStyle()— platform-aware ⌘/Ctrl/Win/Super (guarded for Node).getKeystrokePathForVideo(.keystrokes.json) +normalize/write/persistPending/snapshotkeystroke telemetry, exact mirrors of the cursor telemetry functions.Remaining wiring (Part 3/3 — needs a local dev loop to verify)
The pieces below are pure integration/threading. I have exact anchors for each (from a code-map pass); they compile in isolation but must be verified in
npm run dev:{ showKeystrokes }option throughpreload.setRecordingState+electron-env.d.ts+ theset-recording-statehandler → call the (already-existing)setIsKeystrokeCaptureActive(...)in the start branch;setIsKeystrokeCaptureActive(false)+snapshotKeystrokeTelemetryForPersistence()in every stop branch (native-win @994/996,set-recording-statestop @1838, + any mac/ffmpeg stop paths — grepsnapshotCursorTelemetryForPersistence).get-keystroke-telemetryIPC (mirrorget-cursor-telemetry) +preload.getKeystrokeTelemetry+electron-env.d.tstype.VideoEditor—keystrokeTelemetrystate + aloadKeystrokeTelemetryeffect (mirror thevideoSourcePath-keyed cursor effect including its fresh-recording retry loop), then passkeystrokeTelemetry+showKeystrokes/position/size toVideoPlayback.keystrokeContainersibling ofcursorContainer; instantiatePixiKeystrokeOverlay; attach at both mount sites (~2197/2297);.update(samples, timeMs, baseMaskRef.current, showKeystrokes, freeze)per frame (~2547);.destroy()in cleanup.SettingsPanelcase "cursor"— a "Show Keystrokes"Switch+ positionSelect+ sizeSliderControl, 3 props + defaults, andeffects.*i18n keys in all 10 localesettings.jsonfiles.unlinkthe.keystrokes.jsonalongside the cursor sidecar inproject.ts+prune.ts.frameRenderer.ts/modernFrameRenderer.tsso keystrokes appear in MP4/GIF exports.Manual test plan (once Part 3 lands)
.recordlyproject → overlay replays (sidecar persisted)..keystrokes.jsonis written.Notes