Skip to content

macos: Add configurable materials and glass tint compositing - #1008

Merged
huacnlee merged 4 commits into
longbridge:mainfrom
honsunrise:feat/macos-material-composition
Nov 7, 2026
Merged

huacnlee merged 4 commits into
longbridge:mainfrom
honsunrise:feat/macos-material-composition

Conversation

@honsunrise

@honsunrise honsunrise commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Scope

Expose native material composition without prescribing an application theme:

  • Apply the existing mixBlendMode API on macOS, including text, images and clipped children; normal removes the filter.
  • Add one typed macos.backdrop configuration for AppKit material, blending and activity state.
  • Make glassTintColor support tint updates and native-default restoration on both iOS 26+ and macOS 26+.
  • Allow a custom Rust run_app host to opt into a transparent window. Standard hosts default to opaque windows but can use upstream window attributes to request transparency; an embedded AppView never changes its host window.

The unrelated browser keyboard patch is now a separate PR: #1098. This branch contains no context-menu keyboard or CI-selection changes.

API

MacOsBackdrop is #[non_exhaustive]: construct it with Default and assign fields. Its existing fallback defaults remain Popover, WithinWindow, and Active.

The three new native enums use PropEnum's generated js_name and HostValue::decode paths, with camelCase values. The redundant handwritten name/parse methods and kebab-case overrides introduced by this PR are removed. Existing CSS mixBlendMode values are unchanged.

<View macos={{ backdrop: {
  material: "hudWindow",
  blending: "behindWindow",
  state: "followsWindowActiveState",
} }} />
<View style={{ glassEffect: "regular", glassTintColor: "#4080ff80" }} />

Styled::glass_tint_color accepts IntoReactive<Option<AdaptiveColor>>. Static AdaptiveColor/Hsla/Rgba/Color values retain direct-call ergonomics; optional signals and closures can set and clear the tint.

let tint = signal(Some(AdaptiveColor::rgb(0x4080ff, 0x4080ff)));
let panel = view().glass_effect(GlassEffect::Regular).glass_tint_color(tint);
// In a UI action:
tint.set(None); // native default, not a transparent color

.glass_tint_color(None) also directly restores the default. TS null and removing the style property have the same reset meaning. Transparent color remains an explicit tint.

Native behavior

Explicit macOS material takes precedence over glass, then the existing blur fallback. Effect-kind changes remove the old native view. Tint-only changes retain the glass view, and material views remain noninteractive.

UIKit uses runtime UIGlassEffect lookup, updates tintColor on its effect and assigns the effect back to the same UIVisualEffectView. Blur effects are not sent glass-only selectors. Earlier-system class-unavailable fallback is retained.

AppOptions::transparent defaults to false and now feeds the upstream main-window attributes as an initial default. Explicit launch attributes and later window updates take precedence; the standalone surface no longer keeps a competing transparency flag. No CLI flags, nsh.json keys, per-material utility classes, application color recipes or terminal behavior are added.

Verification scope

Earlier Apple tint/reset verification at 481f4a6e was exercised through real AppKit mouse events and UIKit accessibility activation in a public AppView embedding host on Mac Catalyst. Light/dark native appearance, red/blue, explicit transparent color, native-default restoration and stable glass-view identity passed. UIKit blur also ignored tint updates without replacing its view. WindowServer captures, not in-process screenshots, record the material rendering.

Earlier validation at 481f4a6e used an isolated build directory (not a rerun of the current rebase):

Check Result
Core library 1154 passed; 9 existing ignored
Engine platform selection 23 passed; 320 filtered
macOS backend 87 passed
UIKit lifecycle selection (Catalyst) 2 passed
Core/engine all-target Clippy -D warnings Passed
Paired checker, including checkout applications 32 passed
Bundled guides / changed Rust formatting 5 passed / clean
Native AppKit and UIKit Both appearances, tint/reset, identity, compositor captures verified

Previous rebase verification at 8ddbc7e

Both open PRs are rebased onto origin/main at beeb9fc7707e0d4a195a4f7274f77b30e134c500, without merge commits.

The new upstream window APIs exposed a native interaction regression: after starting with AppOptions::transparent=true, setting the main window opaque left its background alpha at 0, including after a redraw. The integration fix uses the upstream live window state; the same real AppKit scenario now restores alpha 1, survives redraw, and can switch back to alpha 0. Explicit opaque launch attributes win over the host default, and normal hosts remain opaque by default. English/Chinese docs and screenshot-fallback descriptions follow the new upstream contracts.

Fresh local verification after rebase: core 1207 passed / 9 existing ignored; engine platform selection 32 passed / 322 filtered; macOS backend 100 passed; core/engine/macOS all-target strict Clippy passed; bundled guides 5 passed; CLI built; upstream checker all 32 passed. Changed Rust formatting passed. The native window scenario verified both runtime toggling and explicit/default launch precedence. Earlier Website CI exceeded the then-hard Brotli budget by 2,471 bytes. Current upstream has already changed that check to a reporting-only 5,000,000-byte budget; this PR does not modify the budget. The old macOS lint failure was fixed upstream in #1112.

The maintainer closed the independent native-verification follow-up with its environment limitations, not a pass. Earlier author-side native captures remain historical evidence; no new independent verification or older-OS coverage is claimed here. Current local runtime verification targets the rebased window-state integration.

History and merge order

Framework head: 47e7de842b5a585a194a519067ddb74d9ec3b892, linearly rebased onto 4ca2672d30659a63b6358f2942383c6248b2772f; no merge commits.

Companion longbridge/nsh-compat#37 is now merged. Validation uses the checker’s upstream origin/main; no rewrite or push of the merged PR was performed.

Native evidence and reproduction: https://github.com/honsunrise/nsh/tree/bc4e1f6037e6e37b8d20df619f041024d265e5c8/verification/pr1008

Latest CI root causes and correction

All checks on 8ddbc7e3 finished: only Compat and GPUI Gallery failed. GPUI has since been fixed upstream in #1205; the current rebase includes it, with all four material commits unchanged by range-diff. Fresh engine platform tests (32), macOS backend tests (100), and CLI build passed. The original shifted-key assertion also passed on the upstream GPUI implementation in a focused macOS run; a preceding full local run had three setup timeouts, so it is not claimed as 9/9.

Compat is a checker race, not a material regression: the case and example both named desktop shared output and staging directories. It can mix the example bundle with the case script or silently run the same app twice. Earlier green checkout runs do not establish that both desktop apps were covered. The root fix is longbridge/nsh-compat#40: distinct case/example identities and private staging, with no skipped scripts or assertions. All 33 tests passed locally against 8ddbc7e3, and all 17 distinct app outputs were inspected, including both desktop IDs and scripts. That fix has passed its upstream CI and still needs maintainer review/merge; a lucky rerun with the old checker is not proof the race is gone.

The duplicate GPUI fix #1211 was closed in favor of merged #1205. No unrelated GPUI patch was added to this PR. All executed checks on 47e7de84 have now passed, including Linux GPUI Gallery and Web; deployment is skipped by the PR workflow. The green Compat job still checked out old checker f1e4188, so it does not establish that the directory race is eliminated. Merge checker #40 and rerun Compat to verify the corrected harness.

@huacnlee huacnlee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR completes macOS material composition: it applies the existing blend modes, adds native material configuration and live glass tint, and offers a transparent window for custom Rust hosts. Keeping AppKit roles in a macOS-only prop group and product colors outside NSH is reasonable; this is a new public API, so the host integration scope should be explicit before accepting it.

Two changes are needed:

  • Keep the shipped skill guide synchronized (website/docs/coding-guides.md:988, skills/nsh/references/coding-guides.md:988). Adding macos={{…}} only to the website guide breaks website/tests/skills.test.ts:13, which requires verbatim copies. I reproduced bun test website/tests/skills.test.ts: 4 pass, 1 fail. The copies are equal at this commit's parent. Copy the updated guide into the bundled skill; this explains the Website build failure.
  • Make the new public configuration extensible (crates/nsh-core/src/effects.rs:607). MacOsBackdrop derives Default but is missing #[non_exhaustive], required by AGENTS.md's Public Rust structs rule. Add it now so adding material options later does not break exhaustive downstream literals. The external literals in crates/nsh-engine/tests/engine/platform.rs:194 and crates/nsh-platform-macos/src/visual.rs:1327 must then initialize from MacOsBackdrop::default() and assign fields; documentation should demonstrate that construction pattern too.

API scope to resolve/document: AppOptions::transparent can only be set by a custom Rust host calling run_app/constructing AppView. The normal nsh-macos-host CLI and nsh-macos-app::setup leave it false, including generated Rust runners and packaged TSX apps. Thus blending: "behind-window" cannot produce a desktop-transparent standard packaged app through the new TSX API alone. This may be intentional for embedding, but should not be presented as general packaged-app support.

Validation on Linux at 99aa22d8cb5aa9a78079f9959f7f41c80925f3eb:

  • cargo test -p nsh-core --lib: 1,133 passed, 9 ignored.
  • cargo test -p nsh-js --lib: 198 passed, 1 ignored.
  • cargo test -p nsh-engine --test engine macos_props_apply_on_macos_through_the_mount: passed (including the non-macOS control).
  • cargo clippy -p nsh-core -p nsh-js -p nsh-engine --all-targets -- -D warnings: passed.
  • cargo +nightly fmt --all --check: fails only in seven files unchanged by this PR; no formatting failure was reported in its changed files.
  • Website guide parity fails as above. Required Compat also fails at the new material case (no prop macos.backdrop); the PR declares paired checker dependency longbridge/nsh-compat#37. The failing Web Shift+F10 case is the separate existing issue tracked by the fleet, not a demonstrated material-composition regression.

I could not independently verify AppKit rendering on this Linux host. Before merging, a macOS run should capture WindowServer main/PR comparisons (the in-process screenshot API omits compositor effects), light/dark and active/inactive materials, live tint/change/clear, effect-kind transitions, pointer passthrough, transparent custom host, and unchanged embedded host window configuration. On macOS before 26, verify glass fallback without referencing the absent class. No native visual result is claimed here.

🤖 Noop (reviewer) · AI agent acting for @huacnlee

@huacnlee

huacnlee commented Nov 5, 2026

Copy link
Copy Markdown
Member

Mac verification follow-up at 99aa22d8cb5aa9a78079f9959f7f41c80925f3eb (unchanged since the preceding review): blocked by the execution session, not a demonstrated PR failure. A native CoreGraphics probe returned success with zero active displays, CGPreflightScreenCaptureAccess() == false, and no accessible window list. Native screencapture -x also failed with could not create image from display.

WindowServer main/PR composition, blend/reset, material activity, live tint/clear, effect transitions, pointer passthrough, transparent standalone hosts and embedded-window preservation remains unverified. No compositor screenshot, native application test or live settings-change result is claimed. Independent detached worktrees are prepared for resuming in an accessible desktop session; no application/server was started and no user settings were changed. The previous review findings remain unresolved.

🤖 Noop (reviewer) · AI agent acting for @huacnlee

@honsunrise
honsunrise force-pushed the feat/macos-material-composition branch 2 times, most recently from e448d45 to 335ee39 Compare November 6, 2026 02:47
@honsunrise

honsunrise commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the review. Current head: de735c18c829340d4afe706ec1bfa282407a59a8, rebased onto upstream 0d0338ac55e94a004acdb59a333356410c3530c4. The PR is mergeable again; there are no merge commits in its commit range.

  • Added #[non_exhaustive] to MacOsBackdrop; migrated external constructions in the framework and paired checker to Default + field assignment.
  • Synchronized the bundled coding guide; 5/5 guide checks pass.
  • Clarified custom Rust-host-only transparency in Rust API docs and English/Chinese guides. Standard generated/packaged hosts remain opaque; embedded AppView does not modify its NSWindow.
  • Current main now contains a pending-focus fix for single-item menus. The duplicate local OrderWatch implementation was dropped during rebase, rather than adding a second mechanism.
  • Retained explicit browser context-menu key handling and preserved upstream's button === -1 classification. A controlled run with upstream nsh.js and the same WASM still failed Shift+F10 on Chromium/macOS; the corrected implementation passes. Handled keys prevent native defaults to avoid double opening.

Post-rebase local validation: core 1143 passed / 9 existing ignored; menu suite 16 passed; macOS backend 87 passed; original headless context-menu file all 3 passed; real Chromium keyboard and ordinary-click cases both passed; core/base/engine/macOS all-target Clippy -D warnings passed; paired checker all 32 tests passed, including checkout_apps_run and both material-value tests.

The browser host drives a desktop mouse, so the newly added Chrome CI commands select the keyboard and ordinary-click cases. The held-finger test remains unchanged in the full headless run; mouse long press is not substituted for touch input. Extra browser-module checks report 88 pass / 2 skips / 1 existing bidi-link fixture failure, also reproduced on the fixed baseline; no failure was suppressed.

Native evidence and reproduction sources: https://github.com/honsunrise/nsh/tree/0ba1ca241385264382b1970f496e6358ab01e1a7/verification/pr1008
WindowServer captures cover blend/reset, explicit material states, live tint/clear, effect switching and input passthrough. After the live-main rebase, standalone transparency and first-load opaque embedding were exercised again against the rebased code.

Limits: no execution on macOS before 26, and no real active/key-window transition could be obtained in this session. The evidence records these as unverified, not passed.

Paired longbridge/nsh-compat#37 is also rebased and tested locally. Its upstream CI still needs maintainer approval (the approval endpoint returned 403 for my read-only upstream account). Required gates have not been bypassed; neither PR has been merged. The framework Actions run is being followed separately, and local results are not presented as remote CI success.

Remote CI follow-up: watched the final head for one hour. Website build, CI paths, and Rust application (windows-latest) passed; Website deploy was skipped. The other nine checks remained queued. The Core job API reports status: queued, an empty runner_name, and no steps, so there is no execution failure log to fix yet. The watcher timed out locally; the Actions runs were not cancelled. The paired checker remains action_required. @huacnlee could a maintainer check runner admission and approve the paired fork workflow? No remote all-green claim is made.

@honsunrise
honsunrise force-pushed the feat/macos-material-composition branch from 335ee39 to de735c1 Compare November 6, 2026 03:00
@huacnlee

huacnlee commented Nov 6, 2026

Copy link
Copy Markdown
Member

API-focused review at de735c1 (base 0d0338a).

The purpose is sound: expose native material composition that application markup cannot implement, apply the already-existing blend API, and allow a custom Rust host to opt into a transparent window. I would not accept the public API unchanged. The useful surface is three capabilities, not dozens of independent features; typed AppKit roles are appropriate and should not be replaced with an untyped string bag.

Standards

  1. P2: Remove redundant public conversion methods. effects.rs:675-783 adds six name()/parse() methods to enums already deriving PropEnum. nsh-macros/src/lib.rs:1005-1030 generates js_name and HostValue::decode from the same attributes. host_values.rs:119-125 can use field::<Enum, _>(input, key, cx).unwrap_or_default(). This reduces public maintenance and duplicate mappings; test the generated path instead of a handwritten mapping against itself.
  2. P2: Keep native host prop values consistent with the existing vocabulary. effects.rs:645-775 explicitly renames multiword variants to kebab-case (hud-window, behind-window, follows-window-active-state). docs/dev/api-naming.md, Translation, specifies camelCase enum values, and the neighboring iOS material uses ultraThin. These are native props, not CSS keywords. Use hudWindow / behindWindow / followsWindowActiveState and the generated PropEnum path. Existing CSS mixBlendMode values should stay CSS-shaped.
  3. API parity: element/style.rs:2930 accepts only IntoReactive, so the Rust builder cannot directly bind color -> native default -> color, unlike TS null and the backend's Option. Conditional style_with/style_when can omit the declaration, so clearing is possible in Rust, but the dedicated builder is incomplete. Prefer an optional reactive color input with direct-color ergonomics and a reset test. SwiftUI similarly accepts Color? for Glass.tint: https://developer.apple.com/documentation/swiftui/glass/tint(_:)

Design judgment: keep glassTintColor alongside the existing glassEffect style, but implement its tint/reset contract on iOS 26 too before treating it as a coherent Apple glass capability. UIKit already exposes optional UIGlassEffect.tintColor: https://developer.apple.com/documentation/uikit/uiglasseffect/tintcolor . The PR explicitly documents the iOS no-op (style.rs:1597), so this is a completeness/design concern, not an undisclosed runtime regression. If this PR must remain macOS-only, defer the shared tint addition for a focused follow-up rather than create another parallel tint vocabulary.

Spec

The live-tint-clear requirement has the Rust ergonomics gap above. Static inspection found no confirmed defect in material > glass > blur precedence, same-kind updates, native effect removal, or legacy fallback preservation. AppOptions::transparent is now correctly documented as custom-Rust-host-only; it does not make normal packaged TSX apps transparent.

The browser context-menu keyboard change (web/nsh.js:6687 and rust-app.yml:205) solves a separate baseline problem, as the author's comment explains. Move it out of the material PR; it is not needed to define these APIs.

Reference assessment

  • AppKit's NSVisualEffectView separates material, blending mode and activity state; retaining one typed macos.backdrop object is justified: https://developer.apple.com/documentation/appkit/nsvisualeffectview . Keep legacy Active fallback unchanged; consider followsWindowActiveState only for the new explicit API, with activation tests. This is a design choice, not a proven bug.
  • GPUI Kit local revision 56e9153c4e80775cb6e29d5ef6f6b350bbab71b1, crates/base/src/dialog.rs:469: backdrop is an app-supplied overlay element, not an AppKit material equivalent. Reuse its composition discipline, not an unrelated widget name or a new Material component.
  • shadcn Dialog composes parts; it is not a native window-material API: https://ui.shadcn.com/docs/components/radix/dialog . Product color recipes should remain app-owned.
  • Tailwind keeps backdrop filters composable: https://tailwindcss.com/docs/backdrop-filter . Preserve existing backdropFilter/mixBlendMode and avoid new per-material utility families. No new utilities are needed here.

Validation and limits

Read the full API diff, core/style/host decoder, macro generation and macOS effect lifecycle, existing reviews and author response. Independently ran bun test website/tests/skills.test.ts: 5 pass. The previous missing non_exhaustive and guide-sync findings are fixed. No Rust suite rerun or native visual execution is claimed in this API-focused review; the existing T-O0005 native follow-up remains separate.

Remote Core, Linux, Windows, application and Website checks are green, but required Compat is FAILED: run 42153881052, checkout_apps_run step 157 reports no prop macos.backdrop. Its paired checker dependency #37 remains relevant. CI is not all green; this is not a merge recommendation.

Standards: 3 concrete API findings plus an iOS completeness judgment; most significant is the public reset contract. Spec: 2 concerns (shared tint-reset concern and unrelated browser scope); no confirmed backend behavior defect from static review.

🤖 Noop (lead) · AI agent acting for @huacnlee

@honsunrise
honsunrise force-pushed the feat/macos-material-composition branch from de735c1 to 18d2a3c Compare November 6, 2026 08:43

@huacnlee huacnlee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Incremental review at 18d2a3c (previous API audit at de735c1). The branch was rebased onto main 084926b; per git range-diff, the three PR commits differ from de735c1 only by rebase context (AppOptions::notifications, Application.quit() docs). No code from the API audit has changed yet.

Resolved earlier (still holds)

  • MacOsBackdrop is #[non_exhaustive] and built via Default + field assignment (crates/nsh-core/src/effects.rs:606-610).
  • Custom-Rust-host-only transparency is documented (crates/nsh-platform-macos/src/app.rs:207-210, docs/dev/macos.md).

Still open from the API audit (P2, design)

  1. Redundant public converters: BackdropMaterial::name/parse (crates/nsh-core/src/effects.rs:571,582) and MacOsBackdropMaterial/Blending/State name()/parse() (effects.rs:675,695,731…) duplicate the mapping PropEnum already generates. Drop them and decode through field::<Enum, _> in host_values.rs.
  2. Native prop values use kebab case (#[prop(rename = "hud-window")] effects.rs:654, "behind-window" effects.rs:725, follows-window-active-state). docs/dev/api-naming.md and the neighbouring iOS ultraThin use camelCase: hudWindow, behindWindow, followsWindowActiveState. AppKit (NSVisualEffectView.Material.hudWindow) and SwiftUI also spell them this way; kebab case belongs to CSS keywords such as mixBlendMode.
  3. Rust/TS parity for tint reset: glass_tint_color(impl IntoReactive<AdaptiveColor>) (crates/nsh-core/src/element/style.rs:2930) cannot bind color -> native default -> color the way TS null can. Accept an optional reactive color, like SwiftUI Glass.tint(_: Color?) and UIKit UIGlassEffect.tintColor, and add a reset test.
  4. Scope: the iOS 26 glass tint is still documented as a no-op. Either implement it via UIGlassEffect.tintColor, or move glassTintColor into a follow-up so one Apple glass vocabulary covers both platforms.
  5. Commit 18d2a3c (Chromium context-menu keys, crates/nsh-platform-web/web/nsh.js:6536-6690, .github/workflows/rust-app.yml:204-210) is unrelated to materials. Please split it into its own PR. Main has had its own Shift+F10 / held-finger menu fixes (#1011, #1033) since then, so it needs separate review anyway.

API verdict: keep the shape (one typed macos.backdrop object mirroring NSVisualEffectView's material/blendingMode/state, plus AppOptions::transparent for custom hosts). Before accepting it, fix items 1–3 and decide on item 4. Fallbacks are fine: non-macOS platforms ignore macos.backdrop, and CSS backdropFilter is unchanged.

Ran here (Linux): cargo clippy -p nsh-core -p nsh-engine --all-targets -D warnings is clean at 18d2a3c. I could not run the AppKit runtime or the compositor on this host. CI for this head is still pending.

🤖 Noop (reviewer) · AI agent acting for @huacnlee

@honsunrise

honsunrise commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the API review in 481f4a6ed5513968d19a71fde372ce058190eddb, rebased onto dc000056 without merge commits:

  1. Removed the six conversion methods added by this PR. The new enums now use generated PropEnum names and the existing field::<Enum, _>(input, key, cx) decoder helper.
  2. Native values are camelCase (hudWindow, behindWindow, followsWindowActiveState); CSS blend values are unchanged. Updated declarations, callers, docs and paired checker.
  3. glass_tint_color accepts optional reactive colors, retaining direct static-color ergonomics. The regression covers color → None → transparent → color in both themes, including precedence over an earlier declaration. The native fixture also exercises direct None and an optional closure.
  4. Implemented UIKit tint/reset on UIGlassEffect and retained the same UIVisualEffectView for tint-only changes. Blur is not sent glass-only selectors. Actual Catalyst/UIKit and AppKit runs at this head verified both appearances, RGBA versus nil, and view identity. AppKit captures were taken from an active/key LaunchServices app, after compositor settling.
  5. Removed browser keyboard handling and its workflow edits from this PR; it is separate in web: Handle desktop context-menu keyboard requests #1098.

One scope correction to the incremental review: the older iOS BackdropMaterial::name/parse pair already exists in base 084926b (and before this PR). I left that existing public API unchanged rather than add an unrelated removal. Only the redundant converters introduced here were removed.

Reproduction sources, WindowServer captures and source/PID-bound native observations: https://github.com/honsunrise/nsh/tree/bc4e1f6037e6e37b8d20df619f041024d265e5c8/verification/pr1008

Final-head isolated verification is complete: core 1154 passed / 9 existing ignored; engine platform selection 23 passed; macOS backend 87 passed; UIKit lifecycle selection 2 passed; core/engine strict Clippy passed; paired checker all 32 passed, including checkout applications; bundled guides 5 passed; changed Rust formatting clean. The fixture runs and captures are tied to this final head.

Remote gate: all 12 framework checks remain queued. The Core job API reports an empty runner name and no steps, so there is no execution failure log to fix. Paired checker workflow 42196961620 requires maintainer approval. Local verification does not override these gates. The local watcher was stopped; no remote Actions run was cancelled.

Limits: Catalyst's existing standalone run_app hits a nil URLContexts return on this machine; UIKit verification instead used the public AppView embedding API, without modifying that startup code. No old-OS or iPhone-simulator execution is claimed. Strict macOS Clippy is blocked by the base's existing selectable_view.rs:358 drop(active) reference warning. Upstream CI is still queued; paired #37 must land before the framework Compat gate can understand the new assertions. Neither PR has been merged.

@huacnlee

huacnlee commented Nov 7, 2026

Copy link
Copy Markdown
Member

Closing out the independent macOS verification follow-up at observed head 481f4a6ed5513968d19a71fde372ce058190eddb. The maintainer has chosen to stop this environment-blocked verification and retain the coverage gaps explicitly; this is not a passing verification result or a merge recommendation.

Still not independently verified: WindowServer baseline/PR composition, blend/reset, material active/inactive transitions, glass tint update/clear, effect switching, pointer passthrough, transparent custom-host behavior and preservation of embedded-window configuration. The last execution-session probe found zero accessible active displays and no screen-capture access. No reviewer compositor media was produced.

The author's latest native evidence and API-fix response are recorded above; they are not independent execution by this reviewer. This follow-up is complete with those limitations, rather than awaiting another desktop retry. No application/service was left running, user preference changed, or contributor branch pushed or merged by this task.

🤖 Noop (reviewer) · AI agent acting for @huacnlee

@honsunrise
honsunrise force-pushed the feat/macos-material-composition branch from 481f4a6 to 8ddbc7e Compare November 7, 2026 06:57
@honsunrise

Copy link
Copy Markdown
Contributor Author

Rebased onto the fetched origin/main (beeb9fc7707e0d4a195a4f7274f77b30e134c500); current head 8ddbc7e3942ca1926a53a2d0a957710359a49ad2. The branch has no merge commits and is mergeable with the target's subsequent 82dffbb6 update. Companion checker #37 is already merged and was not rewritten.

The rebase exposed an interaction with the new upstream window API: a custom transparent host could switch its window opaque but keep a clear background (alpha 0), even after redraw. AppOptions::transparent now provides only the initial default through the upstream window attributes; explicit launch attributes and subsequent window updates win. The same real AppKit scenario now restores alpha 1, survives redraw, and switches back to alpha 0. Explicit opaque launch and ordinary opaque defaults both passed. Captured content pixels confirmed opaque alpha 1 versus transparent alpha 0. English/Chinese transparency and screenshot documentation was updated.

Fresh local checks: core 1207 passed / 9 existing ignored; engine platform 32 passed; macOS backend 100 passed; core/engine/macOS all-target Clippy -D warnings passed; bundled guides 5 passed; changed Rust formatting clean; upstream checker 32 passed including checkout applications.

The old Website failure was the 4,102,471-byte Brotli output against a 4,100,000-byte limit. Upstream now makes that metric reporting-only with a 5,000,000-byte budget; this PR does not change the budget. The old macOS lint was fixed upstream by #1112, and the new macOS application CI check has passed. Other new checks are still running/queued; no all-green claim is made.

The maintainer's independent native-verification closure remains recorded with its limitations. This author-side rebase smoke is not represented as independent reviewer execution. No PR was merged by this update.

@huacnlee huacnlee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Incremental review of 8ddbc7e against the previously reviewed 18d2a3c (git range-diff: two reviewed commits rebased, the unrelated web context-menu commit dropped, new 7873dd3 and 8ddbc7e).

All points from the earlier API audit are addressed:

  • The redundant public name() / parse() on MacOsBackdropMaterial / Blending / State are removed. Decoding now goes through the shared PropEnum field::<…> path.
  • Native values are camelCase (hudWindow, behindWindow, followsWindowActiveState), matching AppKit names and the existing iOS backdropMaterial values (ultraThin). The compat case and script are updated.
  • Rust glass_tint_color takes impl IntoReactive<Option<AdaptiveColor>>. None resets to the system tint, and static colors still pass directly. TS glassTintColor: null behaves the same way, so Rust and TS now match.
  • iOS 26 UIGlassEffect now applies the tint. A tint change updates the existing effect view instead of rebuilding it, and transparent counts as a real tint, not a reset.
  • The web context-menu change is no longer in this PR (it is #1098).
  • 8ddbc7e makes AppOptions::transparent only an initial default: explicit window attributes and WindowHandle::set win, and a behindWindow material never makes the window transparent. That precedence is right.

Public API verdict. The current surface is macos={{ backdrop: { material, blending, state } }}, glassTintColor / glass_tint_color(Option<…>) and AppOptions::transparent for custom hosts. Each name is self-explanatory, follows AppKit/UIKit vocabulary, has Rust/TS parity and a reset path. No further API changes requested. Accepting a new macOS-only prop group is still the maintainer's call.

Ran locally (Linux):

  • cargo test -p nsh-core filtered to tint/backdrop/material/glass and js::tests: all pass
  • cargo test -p nsh-engine --test engine platform: 32 passed
  • cargo clippy -p nsh-core -p nsh-engine --all-targets -- -D warnings: clean; cargo fmt --check: clean

CI: not green yet.

  • gpui-gallery fails only on form.test.tsx › Shift with a key…, the same failure as main's latest Linux run (42347811185), so this is main drift.
  • compat fails in checkout_apps_run at the desktop case's first step (tap id:case-window-open: nothing to press). This diff doesn't touch that case, and other branches on the same main base pass compat, so it looks like a flake. It is red only on this branch, though: please re-run it, and confirm it passes before merging.
  • check and web are pending.

Not verified here: WindowServer and iOS 26 rendering of the material, the tint and transparency (no macOS/iOS host; see the earlier close-out comment for the remaining native gaps).

🤖 Noop (reviewer) · AI agent acting for @huacnlee

@honsunrise
honsunrise force-pushed the feat/macos-material-composition branch from 8ddbc7e to 47e7de8 Compare November 7, 2026 08:21
@honsunrise

honsunrise commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor Author

CI follow-up: head 47e7de842b5a585a194a519067ddb74d9ec3b892 now rebases on origin/main at 4ca2672d, adopting merged GPUI Shift fix #1205 without adding a separate GPUI patch to this PR. The four PR commits remain equivalent by range-diff. Engine platform 32 and macOS backend 100 tests passed; CLI built.

@huacnlee Compat's independent root cause is fixed in longbridge/nsh-compat#40: cases/desktop and examples/desktop concurrently overwrote the same staging/output paths. That explains both the wrong-screen failure and falsely green runs that executed one app twice. The fix preserves concurrency and every assertion, and verified all 33 tests with 17 distinct app directories. Please review/merge that checker fix before treating a rerun as trustworthy. #1098's CI has now passed all executed checks. No PR merged by this follow-up.

Final CI status on 47e7de84: all executed checks passed, including GPUI Gallery, Linux, Windows and Web; deployment skipped as configured. #1098 is also green. Checker #40 passed its cloud CI (31 tests, fmt and strict Clippy) and is mergeable, but remains open. This Compat run used f1e4188, not #40: the race is still a known harness gap until #40 merges and Compat is rerun. No merge was performed.

huacnlee

This comment was marked as outdated.

huacnlee pushed a commit that referenced this pull request Nov 7, 2026
## Scope
Extracted from #1008 as requested in the material API review. This PR
only handles desktop browser context-menu keyboard dispatch and its CI
coverage; it contains no material/tint APIs.

## Changes
- Handle Shift+F10 and the Menu key after app shortcuts and
editable-field handling.
- Mark keyboard requests as pointer-free, preserving the existing
Chromium `button === -1` classification.
- Prevent the native default only when a custom context menu handled the
request, avoiding duplicate openings.
- Add real-Chrome keyboard and ordinary-click coverage. The full
existing headless file still runs its held-finger case; the Chrome host
drives a desktop mouse, not touch.

## Earlier verification at 4414d25
- Original headless context-menu file: 3 passed.
- Real Chromium/macOS Shift+F10: passed (the unmodified browser
implementation failed to open the menu).
- Browser input/runtime module tests: 66 passed, no skips.
- Branch is based directly on current main, with one commit and no
dependency on #1008.

## Rebase refresh
Head `bd30b584cd58a30157da194d1d8fc89e001054db` is rebased onto
`origin/main` at `beeb9fc7707e0d4a195a4f7274f77b30e134c500`. `git
range-diff` reports the same patch as approved `4414d25f`. After rebase:
JS syntax check and both mouse-module tests passed; the original
headless file passed all 3 cases; real Chromium Shift+F10 and
ordinary-click cases both passed. Windows Menu-key key-up behavior was
not exercised locally.

@huacnlee huacnlee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Check it again, please.

@huacnlee
huacnlee merged commit 701bdce into longbridge:main Nov 7, 2026
14 checks passed
huacnlee added a commit that referenced this pull request Nov 7, 2026
…1227)

## Description

`crates/nsh-platform-web/web/browser/bootstrap.js` is generated, and the
Website workflow checks it is current (`cargo run -p nsh-bundler
--example browser_bootstrap -- --check`). #1008 (the `macos` platform
prop group) and #1216 (`setTheme`) changed its sources without
regenerating it, so that check now fails on `main` and on every pull
request that runs Website (e.g. #1121).

This commit is the generator's output, unchanged: `macos` joins the
browser's `PLATFORM_PROPS`, and the theme gains `setTheme` (op 406), as
the QuickJS runtime already has them.

## Public API

None: the browser runtime catches up with what `main` already declares.

## How to Test

- `cargo run -p nsh-bundler --example browser_bootstrap -- --check`
passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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.

2 participants