Summary
The OpenWorlds macOS app should not show two window frames or two traffic-light
sets. OpenWorlds is the visible product shell, so the native NSWindow chrome
should be hidden or integrated, and the designed OpenWorlds chrome should become
the user's apparent app frame.
The correction PR starts this by hiding the native titlebar/traffic-light
buttons on the main OpenWorlds host window. This issue tracks the follow-through:
make the custom OpenWorlds frame fully functional, draggable, accessible, and
safe.
User-facing impact
Double chrome makes the app feel like a web page trapped inside a wrapper. It
also makes the user wonder which close/minimize/fullscreen controls are real.
The intended experience is a single beautiful OpenWorlds app frame with native
supervision underneath.
Architecture boundary
- Swift/AppKit owns the actual
NSWindow lifecycle.
- OpenWorlds owns the visible frame/chrome.
- The native bridge may expose window commands.
- Browser code must not write game state; window commands are app-shell actions
only.
Proposed architecture
-
Keep the main app window in full-size content mode:
- hidden native title;
- transparent titlebar;
- hidden native close/minimize/zoom buttons;
- OpenWorlds content fills the whole window.
-
Add a narrow native bridge window API:
window.ClawDnDNative.request("windowCommand", { command: "close" })
window.ClawDnDNative.request("windowCommand", { command: "minimize" })
window.ClawDnDNative.request("windowCommand", { command: "zoom" })
-
Wire the OpenWorlds decorative traffic lights to those commands only when the
native bridge is available. In Safari/browser fallback, mark them unavailable
or hide their interactive affordance.
-
Add a reliable drag region:
- either a small AppKit overlay aligned to the OpenWorlds title rail; or
- JavaScript-to-native pointer events if that proves reliable in WKWebView.
-
Preserve accessibility:
- keep a meaningful underlying window title;
- add accessible labels for custom close/minimize/zoom buttons;
- keep menu shortcuts (
Cmd+Q, Window menu) working.
Acceptance criteria
- Normal app launch shows exactly one visible window frame: the OpenWorlds
frame.
- The native macOS titlebar/traffic lights are not visible in normal play.
- The OpenWorlds frame can move the window.
- The OpenWorlds close/minimize/zoom controls invoke native window behavior.
- Browser/Safari fallback does not pretend native window controls are available.
- Debug Control Center may keep standard native chrome.
Validation
swift build --package-path macos/ClawDnDApp
./script/build_and_run.sh --verify
Manual visual smoke:
- capture the app window;
- confirm there is no duplicate chrome;
- move, minimize, zoom, and close through the visible OpenWorlds controls;
- confirm
Option+Command+D still opens the debug control center.
Summary
The OpenWorlds macOS app should not show two window frames or two traffic-light
sets. OpenWorlds is the visible product shell, so the native
NSWindowchromeshould be hidden or integrated, and the designed OpenWorlds chrome should become
the user's apparent app frame.
The correction PR starts this by hiding the native titlebar/traffic-light
buttons on the main OpenWorlds host window. This issue tracks the follow-through:
make the custom OpenWorlds frame fully functional, draggable, accessible, and
safe.
User-facing impact
Double chrome makes the app feel like a web page trapped inside a wrapper. It
also makes the user wonder which close/minimize/fullscreen controls are real.
The intended experience is a single beautiful OpenWorlds app frame with native
supervision underneath.
Architecture boundary
NSWindowlifecycle.only.
Proposed architecture
Keep the main app window in full-size content mode:
Add a narrow native bridge window API:
Wire the OpenWorlds decorative traffic lights to those commands only when the
native bridge is available. In Safari/browser fallback, mark them unavailable
or hide their interactive affordance.
Add a reliable drag region:
Preserve accessibility:
Cmd+Q, Window menu) working.Acceptance criteria
frame.
Validation
Manual visual smoke:
Option+Command+Dstill opens the debug control center.