From 78d6ae4acb890e22aa6a1a3f70710efffa62c6fa Mon Sep 17 00:00:00 2001 From: dallasbpeters Date: Mon, 24 Aug 2026 15:31:08 -0500 Subject: [PATCH 1/2] Stop injecting an !important background over the Studio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Studio's grid background never rendered in the app, and the host was doing it. On dom-ready the Studio window injected: html, body { background: #141415 !important; } `background` is a shorthand, so with !important it resets background-image and background-size to their initial values. Nothing in a stylesheet can outrank it, which is why the grid painted correctly in a browser and computed to `background-image: none` in the app. And because it is injected on dom-ready it lands after first paint — the grid appeared, then vanished, which reads as the page overriding itself. A long time was spent looking for that override inside the page, where it was not. It was belt-and-braces against a white flash on a cold load. The window already sets `backgroundColor: "#141415"`, which is painted before the page exists — earlier than any injected rule can manage — so the injection bought nothing and cost every future page texture. The drag region stays. That one genuinely belongs to the host: it is about the window frame, a served page has no reason to know about it, and the rules are inert in a browser. The editor window has the same shape (`html, body, #root { background: #09090b !important }`) and is left alone: its wallpaper paints on .previewFrame, deeper in the tree, so the shorthand does not reach it. Worth revisiting, not worth changing blind. Co-Authored-By: Claude Opus 5 --- electron/windows.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/electron/windows.ts b/electron/windows.ts index 1fbd686b0..611f86775 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -545,8 +545,25 @@ export function createStudioWindow(url: string): BrowserWindow { const inset = process.platform === "darwin" ? "72px" : "0px"; win.webContents .insertCSS( - `html, body { background: #141415 !important; } - .op-page__main-header { -webkit-app-region: drag; } + /* + * No `html, body { background: … !important }` here. + * + * It was belt-and-braces against a white flash, and the window's own + * `backgroundColor: "#141415"` above already does that — it is painted + * before the page exists, which is earlier than any injected rule can + * manage anyway. + * + * What it also did was reset the page's background-image. `background` + * is a shorthand, so with !important it wiped the Studio's grid and any + * future page texture, and nothing in a stylesheet can outrank it. + * Injected on dom-ready, it landed after first paint: the grid appeared + * and then vanished, which reads as the page fighting itself. Two days + * were spent looking for the override inside the page, where it was not. + * + * The drag region below is the only thing that genuinely belongs to the + * host: it is about the window frame, and it is inert in a browser. + */ + `.op-page__main-header { -webkit-app-region: drag; } .op-page__main-header button, .op-page__main-header a, .op-page__main-header input { -webkit-app-region: no-drag; } From ded0ce3c98ee1740c7c4ceef51d2679a147d7a3e Mon Sep 17 00:00:00 2001 From: dallasbpeters Date: Mon, 24 Aug 2026 15:32:14 -0500 Subject: [PATCH 2/2] Fix the assertion my CFBundleName removal broke MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `matches the display name macOS reads out of Info.plist` still required CFBundleName to equal PRODUCT_NAME. I removed that override two PRs ago to stop Electron looking for "RoleModel Studio Helper.app", and did not run this suite — only the ai-edition tests, the typecheck and biome. It has been red since. Split rather than deleted, because the reason CFBundleName must stay unset is worth asserting: Electron resolves its helper apps from it, electron-builder names them after productName, and setting it aborted the app before it drew a window. The new test says so, and names the FATAL it caused. CFBundleDisplayName still has to equal PRODUCT_NAME — that is the one a person reads. electron suite: 588 passing. Co-Authored-By: Claude Opus 5 --- electron/about.test.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/electron/about.test.ts b/electron/about.test.ts index 79fdea4d4..514e34bd2 100644 --- a/electron/about.test.ts +++ b/electron/about.test.ts @@ -68,7 +68,24 @@ describe("PRODUCT_NAME", () => { it("matches the display name macOS reads out of Info.plist", () => { expect(key("CFBundleDisplayName")).toBe(PRODUCT_NAME); - expect(key("CFBundleName")).toBe(PRODUCT_NAME); + }); + + /* + * CFBundleName must NOT be set, and this is the assertion that says why. + * + * Electron resolves its helper apps from CFBundleName, and electron-builder names + * them after `productName` — so they ship as "Openscreen Helper.app". Setting + * CFBundleName to "RoleModel Studio" sent Electron looking for "RoleModel Studio + * Helper.app", which does not exist, and the app aborted before drawing a window: + * + * FATAL:electron_main_delegate_mac.mm:65] Unable to find helper app + * + * That is what made v0.0.1 unopenable. Nothing is lost by leaving it unset: the + * menu bar reads PRODUCT_NAME because main.ts calls app.setName at module scope, + * and everything a person actually reads comes from CFBundleDisplayName above. + */ + it("leaves CFBundleName unset, so Electron can still find its helper apps", () => { + expect(key("CFBundleName")).toBeUndefined(); }); it("leaves the bundle on disk named upstream's, which the cask and the shim resolve", () => {