Skip to content

Feat/pro recording hud#483

Closed
siyadhkc wants to merge 3 commits intosiddharthvaddem:mainfrom
siyadhkc:feat/pro-recording-hud
Closed

Feat/pro recording hud#483
siyadhkc wants to merge 3 commits intosiddharthvaddem:mainfrom
siyadhkc:feat/pro-recording-hud

Conversation

@siyadhkc
Copy link
Copy Markdown

@siyadhkc siyadhkc commented Apr 21, 2026

Description

This PR implements a "High-End" Recording HUD experience. It ensures the controls remain accessible to the user during active capture while being completely invisible to the final recorded video through system-level content protection.

Motivation

Previously, the HUD would auto-hide to avoid appearing in the video. This made it difficult for users to access "Stop" and "Pause" buttons without using shortcuts. This update solves that UX friction while improving the aesthetic quality of the app.

Type of Change

  • New Feature
  • Refactor / Code Cleanup

Features Added

  • Content Protection: Uses setContentProtection(true) in Electron (Windows/macOS) to exclude the HUD window from screen capture.
  • Pro Recording Bar: The HUD now transitions into a minimalist, semi-transparent status bar during recording.
  • Pulsing Indicator: A subtle red pulsing dot provides clear visual feedback that recording is in progress.

Testing

  1. Launch OpenScreen and start a recording.
  2. Observe the HUD transforming into the compact Recording Bar.
  3. Move or hide the HUD over the recording area.
  4. Stop the recording and verify the final video: The HUD should be completely absent from the file.

Checklist

  • I have performed a self-review of my code.
  • All non-essential changes (unrelated to the HUD) have been removed.

Summary by CodeRabbit

  • New Features

    • Animated ring visualization and pop animation for the countdown
    • Tray menu adds “Show Recording Controls” while recording
  • Improvements

    • Control bar shows a pulsing recording indicator and hides non-essential controls during recording
    • HUD overlay now uses enhanced content protection on Windows and macOS
    • Main HUD is explicitly restored when recording ends

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

Updates to recording UX and window protections: tray menu now offers "Show Recording Controls" and restores HUD when recording stops; HUD overlay gets platform content-protection; countdown overlay gains an SVG ring + animations; HUD bar UI and styles change while recording; button prop type refactor and a small hook cleanup.

Changes

Cohort / File(s) Summary
Electron integration
electron/main.ts, electron/windows.ts
Added tray menu item "Show Recording Controls" that calls showMainWindow() and restores HUD when recording ends; createHudOverlayWindow() now calls win.setContentProtection(true) on win32/darwin.
Countdown overlay
src/components/launch/CountdownOverlay.tsx
Reworked layout to include animated SVG progress ring and animated number; added @keyframes for ring/number; elements keyed by value to force remount and restart animations.
HUD recording UI & styles
src/components/launch/LaunchWindow.tsx, src/components/launch/LaunchWindow.module.css
Added platform state, gated right-side controls on platform, hide source/audio controls during recording, added pulsing red indicator and recordingBar styling, transition classes, and recording-pulse keyframes.
Button props type
src/components/ui/button.tsx
Changed exported ButtonProps from an interface to a type alias using intersection types; no runtime changes.
Hook cleanup
src/hooks/useScreenRecorder.ts
Memoized safeHideCountdownOverlay with useCallback and added it to the cleanup effect's dependency array to stabilize cleanup behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • siddharthvaddem

Poem

late-night code hums, a pulsing red light,
rings spin, windows hide, then return to sight,
tray whispers "show", platforms guard the view,
animations pop, the HUD blinks true —
tiny fixes, kinda cursed, but lowkey smooth.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat/pro recording hud' directly refers to the main feature being implemented (pro recording HUD with content protection and visual indicators) and captures the primary change.
Description check ✅ Passed The PR description covers all major template sections: description, motivation, type of change, features added, testing instructions, and checklist items are all completed with substantive detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1658ff975

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/components/launch/LaunchWindow.tsx Outdated
</div>
</button>
</div>
{!recording && (
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep HUD window controls available while recording on Linux

createHudOverlayWindow enables content protection only on macOS/Windows (electron/windows.ts), so Linux captures can still include the HUD. This new !recording gate removes the sidebar during recording, which also removes the sendHudOverlayHide minimize action; on Linux that leaves users without an in-app way to hide the HUD, so the overlay can be permanently burned into full-screen recordings. Please keep a hide/minimize path available when content protection is unsupported.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/launch/LaunchWindow.tsx (1)

550-580: ⚠️ Potential issue | 🟠 Major

Give the stop/record button a real accessible name.

In recording mode the button’s visible content is a pulsing dot, stop icon, and timer, so assistive tech may announce only the time. Add a stable aria-label/title for start vs stop.

Proposed fix
 				<button
 					className={`flex items-center justify-center rounded-full p-2 transition-[min-width,background-color] duration-150 ${recording ? "min-w-[78px]" : "min-w-[36px]"} ${styles.electronNoDrag} ${
 						recording
 							? paused
 								? "bg-amber-500/10 hover:bg-amber-500/15"
 								: "bg-red-500/12 hover:bg-red-500/16"
 							: "bg-white/5 hover:bg-white/[0.08]"
 					}`}
 					onClick={toggleRecording}
 					disabled={!hasSelectedSource && !recording}
+					aria-label={recording ? t("tooltips.stopRecording") : t("tooltips.startRecording")}
+					title={recording ? t("tooltips.stopRecording") : t("tooltips.startRecording")}
 					style={{ flex: "0 0 auto" }}
 				>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/launch/LaunchWindow.tsx` around lines 550 - 580, The
record/stop button in LaunchWindow.tsx lacks an accessible name; update the
button element (the one using toggleRecording, recording, paused,
hasSelectedSource) to include a conditional aria-label and title that reflect
state — e.g. when recording is false use "Start recording" (or "Start recording
— no source selected" if !hasSelectedSource), and when recording is true use
"Stop recording" (optionally include paused state like "Resume recording" vs
"Pause recording" if you want finer granularity). Ensure both aria-label and
title are set consistently so assistive tech and hover tooltips announce the
correct action.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@electron/main.ts`:
- Around line 226-231: The tray menu label currently uses mainT("common",
"actions.open") with a generic fallback "Show Controls" which may render as
“Open” and confuse users during recording; change the label to use a
recording-specific i18n key (e.g., mainT("tray",
"actions.showRecordingControls") or similar) or a clear literal fallback like
"Show Recording Controls", updating the entry where label is set and keeping the
click handler that calls showMainWindow(); ensure the new i18n key exists in
translations or add it alongside the other tray strings.

In `@src/components/launch/LaunchWindow.module.css`:
- Around line 85-92: The keyframe name recordingPulse violates the stylelint
kebab-case rule; rename the `@keyframes` identifier to recording-pulse and update
the .recordingPulse rule's animation property to use "recording-pulse 1.5s
ease-in-out infinite" so both the `@keyframes` block and the .recordingPulse
animation reference the new kebab-case name.

---

Outside diff comments:
In `@src/components/launch/LaunchWindow.tsx`:
- Around line 550-580: The record/stop button in LaunchWindow.tsx lacks an
accessible name; update the button element (the one using toggleRecording,
recording, paused, hasSelectedSource) to include a conditional aria-label and
title that reflect state — e.g. when recording is false use "Start recording"
(or "Start recording — no source selected" if !hasSelectedSource), and when
recording is true use "Stop recording" (optionally include paused state like
"Resume recording" vs "Pause recording" if you want finer granularity). Ensure
both aria-label and title are set consistently so assistive tech and hover
tooltips announce the correct action.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd917584-01df-4994-bf1f-ff4ce8c0f630

📥 Commits

Reviewing files that changed from the base of the PR and between cccb966 and d1658ff.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • electron/main.ts
  • electron/windows.ts
  • src/components/launch/CountdownOverlay.tsx
  • src/components/launch/LaunchWindow.module.css
  • src/components/launch/LaunchWindow.tsx
  • src/components/ui/button.tsx

Comment thread electron/main.ts
Comment thread src/components/launch/LaunchWindow.module.css Outdated
@siyadhkc
Copy link
Copy Markdown
Author

Hi, thanks for reviewing! Could you please approve the workflows so CI checks can run?

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/launch/LaunchWindow.tsx (1)

555-586: ⚠️ Potential issue | 🟠 Major

Add an accessible name to the primary record/stop button.

Right now screen readers may only get SVG noise or the elapsed time, not “start recording” / “stop recording”. Lowkey important for the HUD’s “always accessible” goal.

♿ Proposed fix
 				{/* Record/Stop group */}
 				<button
+					type="button"
+					aria-label={recording ? t("tooltips.stopRecording") : t("tooltips.startRecording")}
+					title={recording ? t("tooltips.stopRecording") : t("tooltips.startRecording")}
 					className={`flex items-center justify-center rounded-full p-2 transition-[min-width,background-color] duration-150 ${recording ? "min-w-[78px]" : "min-w-[36px]"} ${styles.electronNoDrag} ${
 						recording
 							? paused

If those tooltip keys don’t exist yet, add localized strings alongside the other launch tooltip labels.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/launch/LaunchWindow.tsx` around lines 555 - 586, Add an
accessible name to the primary record/stop button so screen readers get “start
recording” / “stop recording” instead of SVG/noise: update the button in
LaunchWindow (the element using onClick={toggleRecording}, recording, paused and
hasSelectedSource) to include an appropriate aria-label that switches based on
recording/paused state (e.g. use localized tooltip keys next to the other launch
tooltip labels); ensure the aria-label reflects the action (“Start recording” vs
“Stop recording” or “Resume/ Pause” as needed) and falls back to a default
string if localization keys are missing.
src/hooks/useScreenRecorder.ts (1)

406-448: ⚠️ Potential issue | 🔴 Critical

Move safeHideCountdownOverlay above the effect — this currently hits the TDZ.

Line 448 reads safeHideCountdownOverlay in the dependency array before the const is initialized on line 475, so the component throws during render. kinda cursed 2am bug.

🐛 Proposed fix
+	const safeHideCountdownOverlay = useCallback(async (runId: number) => {
+		try {
+			await window.electronAPI.hideCountdownOverlay(runId);
+		} catch (error) {
+			console.warn("Failed to hide countdown overlay:", error);
+		}
+	}, []);
+
 	useEffect(() => {
 		let cleanup: (() => void) | undefined;
 
 		if (window.electronAPI?.onStopRecordingFromTray) {
@@
 			teardownMedia();
 		};
 	}, [teardownMedia, safeHideCountdownOverlay]);
@@
-	const safeHideCountdownOverlay = useCallback(async (runId: number) => {
-		try {
-			await window.electronAPI.hideCountdownOverlay(runId);
-		} catch (error) {
-			console.warn("Failed to hide countdown overlay:", error);
-		}
-	}, []);
-
 	const isCountdownRunActive = (runId?: number) =>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useScreenRecorder.ts` around lines 406 - 448, The effect references
safeHideCountdownOverlay in its dependency array before that function/constant
is declared, causing a TDZ error; move the declaration/definition of
safeHideCountdownOverlay (or wrap it in useCallback) so it appears above the
useEffect that uses it, then update the effect to depend on that
already-initialized safeHideCountdownOverlay; ensure references to
countdownRunId, stopRecording.current, allowAutoFinalize.current,
restarting.current, discardRecordingId.current, screenRecorder, webcamRecorder
and teardownMedia remain valid after reordering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/launch/LaunchWindow.tsx`:
- Around line 634-709: Summary: The quit button remains visible during active
Linux recordings because the outer render condition is wrong; this exposes
app.quit() via sendHudOverlayClose. Fix: prevent rendering or disable the close
button when platform === "linux" && recording by either updating the outer
condition (change (!recording || platform === "linux") to (!recording ||
platform !== "linux")) or, more surgically, wrap the button that calls
sendHudOverlayClose (the button with title t("tooltips.closeApp")) in a
conditional that skips rendering when platform === "linux" && recording (or
replace it with a disabled/hidden variant); keep the minimize/hide HUD button
unchanged. Ensure references: sendHudOverlayClose, recording, platform, and the
close button with title t("tooltips.closeApp").

---

Outside diff comments:
In `@src/components/launch/LaunchWindow.tsx`:
- Around line 555-586: Add an accessible name to the primary record/stop button
so screen readers get “start recording” / “stop recording” instead of SVG/noise:
update the button in LaunchWindow (the element using onClick={toggleRecording},
recording, paused and hasSelectedSource) to include an appropriate aria-label
that switches based on recording/paused state (e.g. use localized tooltip keys
next to the other launch tooltip labels); ensure the aria-label reflects the
action (“Start recording” vs “Stop recording” or “Resume/ Pause” as needed) and
falls back to a default string if localization keys are missing.

In `@src/hooks/useScreenRecorder.ts`:
- Around line 406-448: The effect references safeHideCountdownOverlay in its
dependency array before that function/constant is declared, causing a TDZ error;
move the declaration/definition of safeHideCountdownOverlay (or wrap it in
useCallback) so it appears above the useEffect that uses it, then update the
effect to depend on that already-initialized safeHideCountdownOverlay; ensure
references to countdownRunId, stopRecording.current, allowAutoFinalize.current,
restarting.current, discardRecordingId.current, screenRecorder, webcamRecorder
and teardownMedia remain valid after reordering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7f04bb70-72d3-4910-99ca-12f4707c2722

📥 Commits

Reviewing files that changed from the base of the PR and between d1658ff and 3cb570d.

📒 Files selected for processing (4)
  • electron/main.ts
  • src/components/launch/LaunchWindow.module.css
  • src/components/launch/LaunchWindow.tsx
  • src/hooks/useScreenRecorder.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/launch/LaunchWindow.module.css

Comment on lines +634 to +709
{(!recording || platform === "linux") && (
<div className={`${hudSidebarClasses} ${styles.electronNoDrag}`}>
<div className={`${styles.languageMenuContainer} ${styles.electronNoDrag}`}>
<button
ref={languageTriggerRef}
type="button"
aria-label={t("language")}
aria-expanded={isLanguageMenuOpen}
aria-haspopup="menu"
onClick={() => setIsLanguageMenuOpen((open) => !open)}
className={`h-8 w-8 rounded-lg border border-white/10 bg-white/5 text-white/85 shadow-none transition-colors hover:bg-white/10 ${styles.electronNoDrag}`}
>
<div className="flex w-full items-center justify-center">
<Languages size={13} className="text-white/75" />
</div>
</button>
</div>

{isLanguageMenuOpen
? createPortal(
<div
ref={languageMenuPanelRef}
role="menu"
className={`${styles.languageMenuPanel} ${styles.languageMenuScroll} ${styles.electronNoDrag}`}
style={
{
WebkitAppRegion: "no-drag",
pointerEvents: "auto",
right: `${languageMenuStyle.right}px`,
top: `${languageMenuStyle.top}px`,
maxHeight: `${languageMenuStyle.maxHeight}px`,
} as React.CSSProperties
}
onPointerDown={(event) => event.stopPropagation()}
>
{availableLocales.map((loc) => (
<button
key={loc}
type="button"
role="menuitemradio"
aria-checked={loc === locale}
onClick={() => {
setLocale(loc);
resolveSystemLocaleSuggestion();
setIsLanguageMenuOpen(false);
}}
className={`${styles.languageMenuItem} ${loc === locale ? styles.languageMenuItemActive : ""}`}
>
<span className="truncate">{getLocaleName(loc)}</span>
{loc === locale ? <Check size={11} className="text-white/85" /> : null}
</button>
))}
</div>,
document.body,
)
: null}
{isLanguageMenuOpen
? createPortal(
<div
ref={languageMenuPanelRef}
role="menu"
className={`${styles.languageMenuPanel} ${styles.languageMenuScroll} ${styles.electronNoDrag}`}
style={
{
WebkitAppRegion: "no-drag",
pointerEvents: "auto",
right: `${languageMenuStyle.right}px`,
top: `${languageMenuStyle.top}px`,
maxHeight: `${languageMenuStyle.maxHeight}px`,
} as React.CSSProperties
}
onPointerDown={(event) => event.stopPropagation()}
>
{availableLocales.map((loc) => (
<button
key={loc}
type="button"
role="menuitemradio"
aria-checked={loc === locale}
onClick={() => {
setLocale(loc);
resolveSystemLocaleSuggestion();
setIsLanguageMenuOpen(false);
}}
className={`${styles.languageMenuItem} ${loc === locale ? styles.languageMenuItemActive : ""}`}
>
<span className="truncate">{getLocaleName(loc)}</span>
{loc === locale ? <Check size={11} className="text-white/85" /> : null}
</button>
))}
</div>,
document.body,
)
: null}

{/* Window controls */}
<div className="flex items-center gap-0.5">
<button
className={windowBtnClasses}
title={t("tooltips.hideHUD")}
onClick={sendHudOverlayHide}
>
{getIcon("minimize", "text-white")}
</button>
<button
className={windowBtnClasses}
title={t("tooltips.closeApp")}
onClick={sendHudOverlayClose}
>
{getIcon("close", "text-white")}
</button>
{/* Window controls */}
<div className="flex items-center gap-0.5">
<button
className={windowBtnClasses}
title={t("tooltips.hideHUD")}
onClick={sendHudOverlayHide}
>
{getIcon("minimize", "text-white")}
</button>
<button
className={windowBtnClasses}
title={t("tooltips.closeApp")}
onClick={sendHudOverlayClose}
>
{getIcon("close", "text-white")}
</button>
</div>
</div>
</div>
)}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t expose the quit button during active Linux recordings.

Because sendHudOverlayClose maps to app.quit() in electron/main.ts, Line 700 keeps a data-loss path available while recording on Linux. Keeping “hide HUD” is useful; keeping “quit app” is lowkey risky.

🛡️ Proposed fix
 						{/* Window controls */}
 						<div className="flex items-center gap-0.5">
 							<button
 								className={windowBtnClasses}
 								title={t("tooltips.hideHUD")}
 								onClick={sendHudOverlayHide}
 							>
 								{getIcon("minimize", "text-white")}
 							</button>
-							<button
-								className={windowBtnClasses}
-								title={t("tooltips.closeApp")}
-								onClick={sendHudOverlayClose}
-							>
-								{getIcon("close", "text-white")}
-							</button>
+							{!recording && (
+								<button
+									className={windowBtnClasses}
+									title={t("tooltips.closeApp")}
+									onClick={sendHudOverlayClose}
+								>
+									{getIcon("close", "text-white")}
+								</button>
+							)}
 						</div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{(!recording || platform === "linux") && (
<div className={`${hudSidebarClasses} ${styles.electronNoDrag}`}>
<div className={`${styles.languageMenuContainer} ${styles.electronNoDrag}`}>
<button
ref={languageTriggerRef}
type="button"
aria-label={t("language")}
aria-expanded={isLanguageMenuOpen}
aria-haspopup="menu"
onClick={() => setIsLanguageMenuOpen((open) => !open)}
className={`h-8 w-8 rounded-lg border border-white/10 bg-white/5 text-white/85 shadow-none transition-colors hover:bg-white/10 ${styles.electronNoDrag}`}
>
<div className="flex w-full items-center justify-center">
<Languages size={13} className="text-white/75" />
</div>
</button>
</div>
{isLanguageMenuOpen
? createPortal(
<div
ref={languageMenuPanelRef}
role="menu"
className={`${styles.languageMenuPanel} ${styles.languageMenuScroll} ${styles.electronNoDrag}`}
style={
{
WebkitAppRegion: "no-drag",
pointerEvents: "auto",
right: `${languageMenuStyle.right}px`,
top: `${languageMenuStyle.top}px`,
maxHeight: `${languageMenuStyle.maxHeight}px`,
} as React.CSSProperties
}
onPointerDown={(event) => event.stopPropagation()}
>
{availableLocales.map((loc) => (
<button
key={loc}
type="button"
role="menuitemradio"
aria-checked={loc === locale}
onClick={() => {
setLocale(loc);
resolveSystemLocaleSuggestion();
setIsLanguageMenuOpen(false);
}}
className={`${styles.languageMenuItem} ${loc === locale ? styles.languageMenuItemActive : ""}`}
>
<span className="truncate">{getLocaleName(loc)}</span>
{loc === locale ? <Check size={11} className="text-white/85" /> : null}
</button>
))}
</div>,
document.body,
)
: null}
{isLanguageMenuOpen
? createPortal(
<div
ref={languageMenuPanelRef}
role="menu"
className={`${styles.languageMenuPanel} ${styles.languageMenuScroll} ${styles.electronNoDrag}`}
style={
{
WebkitAppRegion: "no-drag",
pointerEvents: "auto",
right: `${languageMenuStyle.right}px`,
top: `${languageMenuStyle.top}px`,
maxHeight: `${languageMenuStyle.maxHeight}px`,
} as React.CSSProperties
}
onPointerDown={(event) => event.stopPropagation()}
>
{availableLocales.map((loc) => (
<button
key={loc}
type="button"
role="menuitemradio"
aria-checked={loc === locale}
onClick={() => {
setLocale(loc);
resolveSystemLocaleSuggestion();
setIsLanguageMenuOpen(false);
}}
className={`${styles.languageMenuItem} ${loc === locale ? styles.languageMenuItemActive : ""}`}
>
<span className="truncate">{getLocaleName(loc)}</span>
{loc === locale ? <Check size={11} className="text-white/85" /> : null}
</button>
))}
</div>,
document.body,
)
: null}
{/* Window controls */}
<div className="flex items-center gap-0.5">
<button
className={windowBtnClasses}
title={t("tooltips.hideHUD")}
onClick={sendHudOverlayHide}
>
{getIcon("minimize", "text-white")}
</button>
<button
className={windowBtnClasses}
title={t("tooltips.closeApp")}
onClick={sendHudOverlayClose}
>
{getIcon("close", "text-white")}
</button>
{/* Window controls */}
<div className="flex items-center gap-0.5">
<button
className={windowBtnClasses}
title={t("tooltips.hideHUD")}
onClick={sendHudOverlayHide}
>
{getIcon("minimize", "text-white")}
</button>
<button
className={windowBtnClasses}
title={t("tooltips.closeApp")}
onClick={sendHudOverlayClose}
>
{getIcon("close", "text-white")}
</button>
</div>
</div>
</div>
)}
{(!recording || platform === "linux") && (
<div className={`${hudSidebarClasses} ${styles.electronNoDrag}`}>
<div className={`${styles.languageMenuContainer} ${styles.electronNoDrag}`}>
<button
ref={languageTriggerRef}
type="button"
aria-label={t("language")}
aria-expanded={isLanguageMenuOpen}
aria-haspopup="menu"
onClick={() => setIsLanguageMenuOpen((open) => !open)}
className={`h-8 w-8 rounded-lg border border-white/10 bg-white/5 text-white/85 shadow-none transition-colors hover:bg-white/10 ${styles.electronNoDrag}`}
>
<div className="flex w-full items-center justify-center">
<Languages size={13} className="text-white/75" />
</div>
</button>
</div>
{isLanguageMenuOpen
? createPortal(
<div
ref={languageMenuPanelRef}
role="menu"
className={`${styles.languageMenuPanel} ${styles.languageMenuScroll} ${styles.electronNoDrag}`}
style={
{
WebkitAppRegion: "no-drag",
pointerEvents: "auto",
right: `${languageMenuStyle.right}px`,
top: `${languageMenuStyle.top}px`,
maxHeight: `${languageMenuStyle.maxHeight}px`,
} as React.CSSProperties
}
onPointerDown={(event) => event.stopPropagation()}
>
{availableLocales.map((loc) => (
<button
key={loc}
type="button"
role="menuitemradio"
aria-checked={loc === locale}
onClick={() => {
setLocale(loc);
resolveSystemLocaleSuggestion();
setIsLanguageMenuOpen(false);
}}
className={`${styles.languageMenuItem} ${loc === locale ? styles.languageMenuItemActive : ""}`}
>
<span className="truncate">{getLocaleName(loc)}</span>
{loc === locale ? <Check size={11} className="text-white/85" /> : null}
</button>
))}
</div>,
document.body,
)
: null}
{/* Window controls */}
<div className="flex items-center gap-0.5">
<button
className={windowBtnClasses}
title={t("tooltips.hideHUD")}
onClick={sendHudOverlayHide}
>
{getIcon("minimize", "text-white")}
</button>
{!recording && (
<button
className={windowBtnClasses}
title={t("tooltips.closeApp")}
onClick={sendHudOverlayClose}
>
{getIcon("close", "text-white")}
</button>
)}
</div>
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/launch/LaunchWindow.tsx` around lines 634 - 709, Summary: The
quit button remains visible during active Linux recordings because the outer
render condition is wrong; this exposes app.quit() via sendHudOverlayClose. Fix:
prevent rendering or disable the close button when platform === "linux" &&
recording by either updating the outer condition (change (!recording || platform
=== "linux") to (!recording || platform !== "linux")) or, more surgically, wrap
the button that calls sendHudOverlayClose (the button with title
t("tooltips.closeApp")) in a conditional that skips rendering when platform ===
"linux" && recording (or replace it with a disabled/hidden variant); keep the
minimize/hide HUD button unchanged. Ensure references: sendHudOverlayClose,
recording, platform, and the close button with title t("tooltips.closeApp").

@imAaryash
Copy link
Copy Markdown
Collaborator

imAaryash commented Apr 22, 2026

hey @siyadhkc , pls attach video and screenshots of the changes you have made

@siyadhkc siyadhkc closed this by deleting the head repository Apr 22, 2026
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.

2 participants