Skip to content

fix(windows): clip capsule Acrylic to visible regions#497

Closed
Cooper-X-Oak wants to merge 3 commits into
Open-Less:betafrom
Cooper-X-Oak:codex/fix-capsule-gray-edge
Closed

fix(windows): clip capsule Acrylic to visible regions#497
Cooper-X-Oak wants to merge 3 commits into
Open-Less:betafrom
Cooper-X-Oak:codex/fix-capsule-gray-edge

Conversation

@Cooper-X-Oak
Copy link
Copy Markdown
Contributor

@Cooper-X-Oak Cooper-X-Oak commented May 18, 2026

User description

Summary

  • keep Windows capsule Acrylic enabled, but clip the native window region to the visible rounded pill instead of tinting the whole host rectangle
  • update the capsule Acrylic region whenever translation mode changes the host height, unioning a separate rounded badge region for the translation badge
  • realign Windows capsule frontend metrics with the Rust/native contract: 220px host = 196px pill + 12px side insets, with a 52px visible pill height
  • keep QA Acrylic intact because QA fills its native host and does not have capsule's transparent-margin geometry problem
  • add a focused Windows capsule contract test that rejects the old whole-host Acrylic path and rejects a plain rollback

Why this is not a rollback

PR #496 proved that removing capsule Acrylic makes the gray rectangle disappear, but that also gives up the original material fallback. This PR fixes the actual layer violation instead: Acrylic is still used for capsule, but the HWND region is clipped to the real visual shapes before Acrylic is applied. Transparent shadow/badge host margins stay outside the native region, so they cannot be painted gray.

Validation

  • node ./scripts/windows-capsule-acrylic-contract.test.mjs
  • node ./src/lib/capsuleLayout.test.ts
  • npm run build
  • cargo check --manifest-path openless-all/app/src-tauri/Cargo.toml --bin openless

Note: cargo check still emits existing unused/dead_code warnings unrelated to this change.


PR Type

Bug fix, Tests


Description

  • Remove Windows capsule Acrylic

  • Preserve QA Acrylic fallback

  • Keep capsule host transparent

  • Add Acrylic contract tests


Diagram Walkthrough

flowchart LR
  lib["src-tauri/src/lib.rs"] --> host["capsule host stays transparent"]
  layout["src/lib/capsuleLayout.ts"] --> metrics["compact pill + larger host metrics"]
  capsule["src/components/Capsule.tsx"] --> surface["opaque Windows DOM pill"]
  tests["scripts/windows-capsule-acrylic-contract.test.mjs"] --> checks["reject capsule Acrylic regression"]
  config["scripts/windows-ui-config.test.mjs"] --> checks
Loading

File Walkthrough

Relevant files
Bug fix
lib.rs
Remove capsule Acrylic on Windows                                               

openless-all/app/src-tauri/src/lib.rs

  • Deletes the Windows apply_acrylic(...) call for capsule
  • Keeps the capsule host hidden and transparent after positioning
  • Preserves QA Acrylic fallback on Windows
  • Updates comments to explain the transparent-host tradeoff
+9/-21   
Capsule.tsx
Make Windows pill more opaque                                                       

openless-all/app/src/components/Capsule.tsx

  • Disables backdrop-filter for Windows capsule rendering
  • Increases Windows pill opacity and border strength
  • Keeps non-Windows capsule styling unchanged
+3/-3     
capsuleLayout.ts
Separate compact pill from host                                                   

openless-all/app/src/lib/capsuleLayout.ts

  • Restores Windows visible pill metrics to 180x44
  • Keeps the native host width fixed at 220
  • Maintains reserved inset space for shadow and badge geometry
+2/-3     
Tests
capsuleLayout.test.ts
Update capsule metric expectations                                             

openless-all/app/src/lib/capsuleLayout.test.ts

  • Reverts Windows pill metrics to the original compact size
  • Keeps the Windows host width at 220
  • Verifies the transparent host leaves extra centering room
+13/-8   
windows-capsule-acrylic-contract.test.mjs
Add capsule Acrylic regression checks                                       

openless-all/app/scripts/windows-capsule-acrylic-contract.test.mjs

  • Adds a contract test to forbid capsule Acrylic usage
  • Ensures QA still keeps its Acrylic fallback
  • Verifies the pill, host, and transparent wrapper contracts
+53/-0   
windows-ui-config.test.mjs
Adjust Windows UI config assertions                                           

openless-all/app/scripts/windows-ui-config.test.mjs

  • Updates Windows capsule metric assertions to the new layout
  • Checks the host still reserves shadow and badge space
  • Keeps existing UI configuration validation coverage
+6/-2     

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 18, 2026

PR Reviewer Guide 🔍

(Review updated until commit 4b28d92)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

496 - Partially compliant

Compliant requirements:

  • Remove the Windows Acrylic treatment from the capsule window.
  • Keep capsule/QA positioning, visibility, and lifecycle behavior unchanged.
  • Keep the main window Mica path unchanged.

Non-compliant requirements:

  • Remove the Windows Acrylic treatment from the QA window.

Requires further human verification:

  • Verify the Windows capsule appearance on real hardware/backgrounds, since the new non-backdrop rendering is only fully assessable visually.
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Material regression

On Windows the capsule now disables backdrop filtering entirely and makes the pill nearly opaque. That removes the translucent material fallback the capsule previously had, so any Windows launch will show a flatter white chip instead of a blurred surface.

const useBackdrop = os !== 'win';

return (
  <div
    style={{
      display: 'inline-flex',
      alignItems: 'center',
      justifyContent: 'space-between',
      gap: 4,
      padding: '0 8px',
      width: metrics.width,
      height: metrics.height,
      boxSizing: metrics.boxSizing,
      borderRadius: 999,
      background: os === 'win' ? 'rgba(255, 255, 255, 0.96)' : 'rgba(255, 255, 255, 0.85)',
      backdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
      WebkitBackdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
      border: os === 'win' ? '1px solid rgba(255, 255, 255, 0.78)' : '1px solid rgba(255, 255, 255, 0.55)',

@Cooper-X-Oak
Copy link
Copy Markdown
Contributor Author

Closing this duplicate path so we can continue on top of #496 instead. The #496-based follow-up is here: HKLHaoBin#1

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit fb339f9

@Cooper-X-Oak Cooper-X-Oak force-pushed the codex/fix-capsule-gray-edge branch from fb339f9 to 76a7861 Compare May 18, 2026 16:17
@Cooper-X-Oak Cooper-X-Oak changed the title fix(windows): keep capsule host transparent fix(windows): clip capsule Acrylic to visible regions May 18, 2026
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 76a7861

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 473581c

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 4b28d92

@Cooper-X-Oak
Copy link
Copy Markdown
Contributor Author

Windows capsule HITL evidence for 4b28d92

I re-tested the current #497 head after replacing the DWM/region approach with the transparent-host + DOM-pill boundary.

Why this matches the original report

The original user-visible bug was a gray/transparent rectangular host behind the Windows capsule. The root cause was applying HWND-level material to a native host that is intentionally larger than the visible pill. That host needs transparent margins for shadow, badge, and animation room, so full-window Acrylic/SystemBackdrop paints those margins gray.

This revision keeps the capsule native host transparent and lets the DOM pill own the visible capsule shape. It also explicitly prevents the two regression paths that caused trouble:

  • no apply_acrylic(&capsule, ...)
  • no capsule DwmEnableBlurBehindWindow / DWMWA_SYSTEMBACKDROP_TYPE / SetWindowRgn

QA still keeps Acrylic because its panel fills the native host; capsule is different because its host has transparent margins.

HITL screenshot

Windows capsule HITL crop

Full-screen capture: https://raw.githubusercontent.com/Cooper-X-Oak/openless/codex/pr497-evidence-20260519-083148/pr497-capsule-hitl/screen-green-bg-hitl.png

Raw metadata: https://raw.githubusercontent.com/Cooper-X-Oak/openless/codex/pr497-evidence-20260519-083148/pr497-capsule-hitl/meta.json

Pixel gate

Environment: Windows, 125% scale, solid green background RGB(37,200,81) behind the capsule.

  • host rect: 275x105 physical pixels, corresponding to 220x84 at 125% scale
  • top-left / top-right / bottom-left / bottom-right / left-at-pill-center / right-at-pill-center: all sampled as RGB(37,200,81)
  • maxSampleDistanceFromGreen = 0
  • transparentMargins = true
  • noHostSizedGrayRect = true
  • compactVisualWidth = true
  • compactVisualHeight = true
  • human HITL gate: pass

macOS safety check

This change should not remove the existing macOS glass behavior:

  • Capsule.tsx now uses const useBackdrop = os !== 'win';, so macOS still keeps backdropFilter: blur(28px) saturate(180%) and the original rgba(255, 255, 255, 0.85) pill surface.
  • capsuleLayout.ts only restores compact Windows pill metrics inside if (os === 'win'); macOS metrics remain 176x42.
  • lib.rs removes only the Windows capsule material/region path. The macOS main-window apply_vibrancy(... NSVisualEffectMaterial::HudWindow ...) path is unchanged.

Validation already run locally:

  • node .\scripts\windows-capsule-acrylic-contract.test.mjs
  • node .\src\lib\capsuleLayout.test.ts
  • npm run build
  • cargo check --manifest-path .\openless-all\app\src-tauri\Cargo.toml --bin openless
  • cargo build --manifest-path .\openless-all\app\src-tauri\Cargo.toml --bin openless
  • Windows HITL screenshot + pixel gate above, triggered via OPENLESS_HOTKEY_INJECTION_DRY_RUN=1 and openless.exe --toggle-dictation without keyboard injection

@Cooper-X-Oak
Copy link
Copy Markdown
Contributor Author

Closing per author request. I am pausing involvement with this project for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant