Skip to content

Add in-app Game Theme Editor (BL-16323) - #8086

Closed
hatton wants to merge 9 commits into
masterfrom
game-theme-editor
Closed

Add in-app Game Theme Editor (BL-16323)#8086
hatton wants to merge 9 commits into
masterfrom
game-theme-editor

Conversation

@hatton

@hatton hatton commented Jul 20, 2026

Copy link
Copy Markdown
Member

In-app Game Theme Editor

Adds a self-contained editor for Bloom game themes (named sets of CSS custom properties that style drag-activity game pages), reachable from the Games tool's theme chooser in the Edit-tab toolbox.

What's here

  • src/gameThemeEditor/ — a self-contained React/TypeScript editor project (color pickers, contrast checker, draggable/resizable floating panel). It depends on nothing in BloomBrowserUI; the only coupling is the IGameThemeEditorHost contract plus mount()/unmount().
  • Host bridgebookEdit/toolbox/games/gameThemeEditorHost.ts mounts the editor over the live page for real-time recoloring; ThemeChooser.tsx gains New…, Customize…, and an edit (pencil) button that open it.
  • C# GameThemeEditorApi — reads/writes theme variables (collection + developer-only factory source).
  • Theme contrast fixes — adjustments in gamesThemes.less (BL-16323).

This session's follow-up work (on top of a fresh master merge)

  • Brought the branch up to date with master (yarn→pnpm migration + new tsgo type-check gate).
  • Build resolution: because the editor lives in a sibling directory, master's stricter pipeline couldn't resolve its bare deps. Added tsconfig paths (type check) and a small, build-only, editor-scoped Vite plugin (production build) — the build-time counterpart to the dev server's existing optimizeDeps handling.
  • Localization: added the three missing theme-chooser strings to BloomLowPriority.xlf (NewTheme, CustomizeTheme, EditThemeColors) and routed the edit-button tooltip through useL10n.

Notes for reviewers

  • The editor's own internal strings (color picker, contrast checker, etc.) are intentionally hardcoded English for now — it's an experimental, self-contained feature; localizing them would mean threading strings through the host contract.

Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-16323

Devin review


This change is Reviewable

hatton and others added 2 commits June 22, 2026 16:09
Introduce a standalone Game Theme Editor web app (src/gameThemeEditor) and
wire it into Bloom. The editor lets users view and customize the CSS color
variables that drive game themes, with a color picker, a per-color outline,
and a contrast checker that flags pairs failing WCAG/UI contrast minimums.

- New React/TypeScript app under src/gameThemeEditor with its own build
  (package.json, tsconfig, host interface) hosted in a draggable/resizable frame.
- Host integration from the Games toolbox: ThemeChooser launches the editor and
  gameThemeEditorHost bridges editor and Bloom.
- C# GameThemeEditorApi to read/write theme variables, registered in
  ProjectContext.
- BloomBrowserUI build wiring (vite.config, tsconfig, package.json, yarn.lock).
Brings the in-app Game Theme Editor branch (364 commits behind) up to
date with master. Notable resolutions:

- Adopted master's yarn->pnpm migration: removed yarn.lock, kept the
  pnpm-lock.yaml / pnpm-workspace.yaml from master.
- package.json: took master's exact version pins over the branch's ^
  ranges (react-table 6.11.5, react-tabs 3.2.2, etc.), while preserving
  react-rnd 10.4.13 which the editor feature (gameThemeEditorHost.ts)
  depends on and master never carried.
- Ran `pnpm install --lockfile-only` so pnpm-lock.yaml includes react-rnd.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a self-contained, floating Game Theme Editor reachable from the Games toolbox theme chooser. The editor lives in a sibling src/gameThemeEditor/ project and communicates with Bloom exclusively through the IGameThemeEditorHost contract, keeping coupling strictly one-directional.

  • Editor project (src/gameThemeEditor/): a React/TypeScript panel with a CSS-variable hierarchy tree, color picker with WCAG contrast checking, and draggable/resizable frame using react-rnd. The DOM+canvas double-resolution approach in contrastUtils.ts correctly handles color-mix() and translucent colors.
  • Host bridge (gameThemeEditorHost.ts): mounts the panel into the top-level document (so it can be dragged across the full Bloom window), drives live recoloring via an injected bloom-ui <style> element, and correctly handles save/rename/delete by writing to customBookStyles2.css or customCollectionStyles.css via new C# endpoints.
  • Theme chooser (ThemeChooser.tsx): gains New…/Customize… dropdown items, a pencil edit button (hidden for non-developers on factory themes), and per-item header-color previews.

Important Files Changed

Filename Overview
src/BloomBrowserUI/bookEdit/toolbox/games/ThemeChooser.tsx Extends the theme chooser with New/Customize dropdown items, a pencil edit button, and live theme preview colors; uses bare useEffect instead of useMountEffect per AGENTS.md guidance.
src/BloomBrowserUI/bookEdit/toolbox/games/gameThemeEditorHost.ts New host bridge that mounts the editor into the top-level document, manages live CSS-variable preview via injected styles, and implements the IGameThemeEditorHost contract cleanly.
src/BloomExe/web/controllers/GameThemeEditorApi.cs New API controller that reads/writes theme CSS rules (book, collection, factory source); uses Regex.Escape on slug values and documents the invariant clearly.
src/gameThemeEditor/src/GameThemeEditorPanel.tsx Main editor UI with color editing, save/delete actions, and live recoloring; contains a trivially redundant ternary in buttonStyle (both branches produce bloom.blue).
src/gameThemeEditor/src/index.tsx Clean mount/unmount entry point; reuses the React root on re-mount and anchors the Emotion cache to the container document's head, handling cross-document embedding correctly.
src/gameThemeEditor/src/contrastUtils.ts WCAG contrast helpers using a DOM+canvas double-resolution approach to correctly handle color-mix() and translucent colors; logically sound.
src/BloomBrowserUI/vite.config.mts Adds a scoped Vite plugin to re-resolve the game theme editor's bare imports from BloomBrowserUI/node_modules, plus an alias and optimizeDeps entries; cleanly scoped to editor importers only.
DistFiles/localization/en/BloomLowPriority.xlf Adds three new l10n strings for the theme chooser UI; translate=no issue was flagged in a previous review thread.
src/content/templates/template books/Games/gamesThemes.less Intentional contrast fixes for BL-16323: simplifies white-and-orange-on-blue and garden-path themes by removing redundant overrides and alphabetizing declarations.
src/gameThemeEditor/src/themeModel.ts Defines the CSS variable hierarchy, slugify/displayName helpers, and the tree builder; the parent chain correctly mirrors gamesThemes.less .apply-game-theme().

Reviews (3): Last reviewed commit: "Revive game theme editor on current mast..." | Re-trigger Greptile

Comment on lines 354 to 372
<note>{0} will be replaced with the name of the collection that the user currently has open for editing.</note>
</trans-unit>
<trans-unit id="EditTab.Toolbox.Games.NewTheme" translate="no">
<source xml:lang="en">New…</source>
<note>ID: EditTab.Toolbox.Games.NewTheme</note>
<note>An item in the game "Theme" dropdown in the Games tool of the Edit tab's toolbox. Choosing it starts a brand-new game theme in the theme editor. The trailing ellipsis (…) signals that an editor will open.</note>
</trans-unit>
<trans-unit id="EditTab.Toolbox.Games.CustomizeTheme" translate="no">
<source xml:lang="en">Customize…</source>
<note>ID: EditTab.Toolbox.Games.CustomizeTheme</note>
<note>An item in the game "Theme" dropdown in the Games tool of the Edit tab's toolbox. Choosing it creates a new game theme that starts as a copy of the theme currently applied, then opens it in the theme editor. The trailing ellipsis (…) signals that an editor will open.</note>
</trans-unit>
<trans-unit id="EditTab.Toolbox.Games.EditThemeColors" translate="no">
<source xml:lang="en">Edit theme colors</source>
<note>ID: EditTab.Toolbox.Games.EditThemeColors</note>
<note>Tooltip (hover text) on the pencil/edit button next to the game "Theme" dropdown in the Games tool of the Edit tab's toolbox. Clicking the button opens the game theme editor to change the current theme's colors.</note>
</trans-unit>
</body>
</file>

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.

P1 translate="no" on user-visible strings prevents localization

All three new <trans-unit> entries carry translate="no". In XLIFF this attribute tells Crowdin (and any other XLIFF-aware toolchain) that the segment must NOT be translated and should be passed through as-is. "New…", "Customize…", and "Edit theme colors" are real UI strings that end up in the toolbox via useL10n/<Div l10nKey=...>, so Crowdin will silently skip them and non-English users will always see the English text regardless of their locale. The attribute should be removed from all three entries (or, if the intent is deliberately English-only for now, that choice should be documented here rather than signalled via translate="no").

Context Used: AGENTS.md (source)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Claude Opus 5] Half agreed, and leaving this open deliberately.

Where this is mistaken: translate="no" on a new entry is this repo's documented convention, not an oversight. .github/skills/xlf-strings/SKILL.md says "Always mark new entries translate=\"no\" unless instructed otherwise", the intent being that a string is withheld from translators until its wording has settled, so nobody pays to translate text that then changes. Devin raised the same point independently and has since withdrawn it for exactly this reason.

Where this is right: the observable consequence you describe is real — until the attribute is removed, non-English users see "New…", "Customize…" and "Edit theme colors" in English next to menu text that is translated.

So the real question is whether the wording is final enough to flip now, which is the developer's call rather than something to decide from convention alone. It is in this run's preflight decision report; this thread stays open until that decision comes back, at which point the outcome gets recorded here.

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.

Thanks for the correction — that's fair, and the distinction you've drawn is exactly right.

My comment conflated two separate questions: (1) is translate="no" correct per convention? and (2) is the wording settled enough to drop it? The first has a clear answer (yes, per the documented convention), and I shouldn't have flagged it as a defect. The second is genuinely open and is the developer's call, so keeping this thread open pending that decision makes sense.

For what it's worth, I already have a rule (from a previous correction on this same pattern) that says not to flag translate="no" on new XLF entries as a defect. The fact that I fired anyway suggests the rule needs tightening — the right framing for future reviews is: new entries with translate="no" are correct; worth a note only if the strings look stable enough to flip now, and even then as a nudge rather than a defect.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@hatton
hatton force-pushed the game-theme-editor branch from e053636 to 42f492d Compare July 20, 2026 22:15
…es (BL-16323)

Brings the in-app game theme editor branch back to life on top of a freshly
merged master, and finishes the game-theme contrast and localization work.

Build: the editor is a self-contained project whose source lives in a sibling
directory (src/gameThemeEditor/src), outside BloomBrowserUI. After master's
yarn->pnpm migration and its new tsgo type-check gate, two build steps could no
longer resolve the editor's bare dependency imports (@emotion/react,
@emotion/cache, react-dom, react-rnd) by walking up out of that folder:
- Type check: added tsconfig "paths" entries mapping those specifiers into
  BloomBrowserUI/node_modules, mirroring the existing "react"/"gameThemeEditor"
  mappings.
- Production build (vite / Rollup): added a small, build-only Vite plugin that
  re-resolves those ids from BloomBrowserUI's root, scoped to importers inside
  the editor directory so the rest of the app is untouched and react stays
  deduped. This is the build-time counterpart to the dev server's existing
  optimizeDeps.include handling.

Localization: added the three missing Games-tool theme-chooser strings to
BloomLowPriority.xlf (NewTheme "New…", CustomizeTheme "Customize…",
EditThemeColors "Edit theme colors"), each translate="no" with a translator
context note, and routed the edit-button tooltip through useL10n.

Themes: further contrast fixes to the game themes (gamesThemes.less).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hatton
hatton force-pushed the game-theme-editor branch from 42f492d to 8624b7e Compare July 20, 2026 22:28
Comment thread DistFiles/localization/en/BloomLowPriority.xlf
/// <summary>Upsert the theme's rule into the file at <paramref name="path"/>, and—when the
/// theme was renamed—remove the rule for its previous slug so a rename does not leave a
/// duplicate behind.</summary>
private static void WriteThemeToFile(string path, ThemeDto theme)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Devin] Investigate: Theme rename removes the old rule only from the file it's saving into

When a theme is renamed, the old CSS rule is removed only from the stylesheet the renamed theme is being written to. If the original rule lived in a different location (e.g. defined at collection level but now saved to the book, or vice-versa), the old rule is never removed and can linger as an orphaned/duplicate theme rule.

Pre-existing editor logic; left open for developer assessment (see preflight decision report).

Comment thread src/BloomBrowserUI/vite.config.mts
@hatton

hatton commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

[Claude Opus 4.8] Consulted Devin on 2026-07-20 (22:36 UTC) up to commit 8624b7e6e.

1 Bug — "New theme-menu labels will never appear in other languages" (translate="no"): posted as a thread, left open — it's a developer decision (repo convention vs. matching the translatable sibling strings). See preflight decision report.

2 Investigate flags:

  • Theme rename removes the old rule only from the file it saves into — posted, left open for developer assessment.
  • Dev server may not resolve the editor's bare imports — posted and ✅ resolved: the resolver Vite plugin now runs in all modes (dev included), so this is addressed.

7 Informational flags (not posted — low signal): pencil button clickable while editor open; ColorPicker outside-click effect re-subscribes each render; contrast probe/cache never invalidates; C# theme-block rewrite relies on the flat-declaration invariant (verified to hold); white-and-orange-on-blue header background semantics changed (intentional contrast fix); stale mount-location comments; unguarded localStorage write.

CI (pr-automation, track) green; Greptile green (its one P1 is the same translate="no" issue).

hatton and others added 4 commits July 27, 2026 16:50
…X (BL-16323)

Two preflight fixes to the game theme editor branch:

pnpm-lock.yaml had been rewritten in raw pnpm style (2-space indent, single
quotes) instead of the repo's prettier-formatted style (4-space, double
quotes). Nothing about the dependency graph actually changed -- the file is not
in .prettierignore, so prettier owns it -- but the reformatting inflated the
diff to ~30,400 lines and would have made merging master (151 commits ahead)
needlessly painful. Running prettier over it reduces the change to the 58 lines
that genuinely add react-rnd and its transitive deps (react-draggable,
re-resizable, tslib).

tsconfig.json was missing path mappings for @emotion/react/jsx-runtime and
jsx-dev-runtime. The editor sets jsxImportSource to @emotion/react, so every
.tsx file under ../gameThemeEditor resolves its JSX factory through that
subpath; from the sibling directory the lookup failed and all eight components
reported TS2875. Because TS2875 is not one of the blunder-class codes the
typecheck gate fails on, this went unnoticed and the editor's JSX was silently
going unchecked. With the mappings in place the editor type-checks clean, so
this closes the hole without hiding any existing errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UpsertThemeRule passed the generated CSS rule to Regex.Replace as a replacement
string. .NET interprets "$" in a replacement as a substitution token ($1, $&,
${name}), so any theme variable whose value contained a "$" would have been
silently mangled when overwriting an existing rule -- while appending a brand-new
rule, which does not go through Regex.Replace, would have written it correctly.
Substituting via a MatchEvaluator inserts the rule verbatim. Slugs are unaffected
either way (slugify() strips them to [\w-]).

GameThemeEditorPanel decided whether to auto-focus and select the name field by
testing displayName.startsWith("Untitled"). The panel already computes isNewTheme
a hundred lines earlier from the host's explicit "new" signal
(getNewThemeName() !== null), so the string sniff was both redundant and wrong at
the edges: it would have selected the name of an existing user theme actually
called something like "Untitled sketch", and it silently coupled focus behavior to
the English wording of the suggested name, so localizing "Untitled Theme N" later
would have broken it with no compile-time signal. Use isNewTheme.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	DistFiles/localization/en/BloomLowPriority.xlf
…on/cache (BL-16323)

Two findings from Devin's review of 5aee1b2.

ThemeChooser's two mount-only effects (the editor open-state subscription and the
developer-capability fetch) were written as bare useEffect(..., []). The
front-end AGENTS.md asks for the useMountEffect helper instead, which exists
precisely so the single justified exhaustive-deps suppression lives in one place
rather than being rewritten per call site. No runtime change; the third effect in
this file has real dependencies and is left alone.

@emotion/cache was imported by the editor (src/gameThemeEditor/src/index.tsx) but
declared nowhere: BloomBrowserUI depends only on @emotion/core, /react and
/styled, so the package was reaching it as a transitive dependency of
@emotion/react. That resolves today, and the production bundle builds, but pnpm's
isolated node_modules layout only guarantees direct dependencies at the project
root, so this was working by accident of the current layout rather than by
declaration. Added it as a direct dependency pinned to 11.10.5 -- the version
already resolved in the tree -- so nothing else moves.

The lockfile is re-prettified after the install: pnpm rewrites it in its own
2-space style, which is what produced the ~30,000-line diff cleaned up in
7716b7b. The net lockfile change here is 41 lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@@ -65,36 +65,19 @@
}

.bloom-page.game-theme-white-and-orange-on-blue {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Devin] Investigate: white-and-orange theme drops the control-button-bg contrast override

Rewriting .bloom-page.game-theme-white-and-orange-on-blue removed two colour overrides that had been added for this very ticket, along with the comments explaining them:

  • --game-control-button-bg-color: #ffce8f;
  • --game-checkbox-outline-color: white;

The same --game-control-button-bg-color override (#ffdccf) was also dropped from .game-theme-coral-reef.

Why this matters. With the override gone, the value falls back through the defaults in this file — --game-control-button-bg-color: var(--game-primary-bg-color) (line 43) and --game-primary-bg-color: var(--game-primary-color) (line 20) — so it lands on the theme's #ffb453. The comment that was deleted alongside it recorded that this orange is 2.81:1 against the blue page, just under the 3:1 minimum for UI components, which is exactly why the brighter #ffce8f (3.4:1) was introduced. --game-control-button-bg-color is used as a real background (Games.less:586), so this is visible, not cosmetic. The deleted checkbox-outline comment likewise recorded a move from a nearly-invisible grey (1.32:1) to white (4.95:1).

I verified that neither derivation was changed by this branch, so the fallback really does resolve to the lower-contrast colour.

This looks like an unintended side effect of round-tripping the factory themes through the new editor: the output is alphabetised, comments are stripped, and dropRedundantColors removes values it considers derivable — but these two were deliberately not the derived value.

Flagging rather than fixing, because re-tuning these themes may well have been intentional. Raised for a decision in the preflight report.

Comment thread src/BloomBrowserUI/bookEdit/toolbox/games/ThemeChooser.tsx
Comment thread src/gameThemeEditor/src/index.tsx Outdated
@hatton

hatton commented Jul 27, 2026

Copy link
Copy Markdown
Member Author

[Claude Opus 5] Consulted Devin on 2026-07-27 (17:15 UTC) up to commit 5aee1b2ab, and re-triggered for d979ffc77 after the fixes below.

That review raised 2 bugs, 4 investigate flags and 11 informational items. Outcomes:

  • Mount-only effects should use useMountEffect — correct; fixed in d979ffc. thread
  • @emotion/cache was never declared as a dependency — correct; it was resolving only as a transitive of @emotion/react. Declared directly in d979ffc. thread
  • white-and-orange theme lost its contrast overrides — confirmed, and it also affects coral-reef. Left open for a decision. thread
  • Theme rename can orphan the old rule — confirmed real; left open for a decision. thread
  • New menu labels marked translate="no" — Devin withdrew this itself on re-review, since the repo convention requires it for new entries. thread
  • Dev server may not resolve the editor's bare imports — stale: the env.command === "build" restriction it cites was already removed in 8624b7e, so no action.

The 11 informational items were reviewed and none warranted a change. CI is green.

…6323)

Two more findings from Devin's review of d979ffc.

mount() created a fresh Emotion cache on every call, anchored to the page
document's <head>, and unmount() only tore down the React root. Emotion's <style>
elements live in that head rather than inside the container, so removing the
container (which the host does on close) left them behind -- and because the host
recreates the container on each open, every open/close cycle added another full
set of style nodes to the page. The cache is now kept alongside the root and
reused for re-renders instead of being recreated, and unmount() calls
cache.sheet.flush(), Emotion's own API for removing the elements it inserted.

The default save target was chosen with a stacked ternary. The root AGENTS.md
explicitly rules that out ("Avoid stacking/nesting ternary operators ... Use an
if/else-if chain (or a switch) instead"), so it is now an if/else-if chain. No
behavior change.

Verified with typecheck, the full Vitest suite, and an isolated production Vite
build (agent-vite), since the Emotion change affects real bundling rather than
just types.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread src/gameThemeEditor/src/index.tsx
Comment thread src/gameThemeEditor/src/GameThemeEditorPanel.tsx
Comment thread src/gameThemeEditor/src/GameThemeEditorPanel.tsx Outdated
…6323)

Devin promoted this to a bug on re-review of fae350e, and it holds up.

save() guards against writing over a different theme with
`theme.slug !== startingSlug && host.themeExists(theme.slug)`. But startingSlug
is whatever theme the page was displaying when the editor opened, and for "New…"
and "Customize…" the host deliberately switches the page to the base theme first.
So if the user names the new theme after the one it was based on, the first half
of the condition is false, the existence check never runs, and Save writes that
slug with no warning. Where the base is a custom book/collection theme, that
overwrites its colors outright; where it is a factory theme, it silently creates
an override the user did not ask for.

Comparing against renameFromSlug instead gives exactly the intended semantics:
it is "" for a new theme, so any existing name now trips the guard; it equals the
theme's own slug when editing in place, so saving over yourself is still allowed;
and it is the old slug when renaming, so the new name is still checked. The guard
already had the right intent -- it was just comparing against the wrong thing.

Likelihood is low, since new themes are pre-seeded with "Untitled Theme N" and the
user has to retype the base name, but the failure is silent data loss, so it is
worth the one-word fix.

Also updates two PAPERCUTS entries with what this run cost:
- the agent-dotnet environmental-failure baseline is 19 now, not 9, and needs the
  trx logger to enumerate; recording it by test-class pattern rather than count.
- the pnpm-lock format drift is prettier's formatting, not an old pnpm style, so
  `prettier --write pnpm-lock.yaml` after an install fixes it in one step -- no
  hand-patching of hashes as that entry previously advised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread src/BloomBrowserUI/bookEdit/toolbox/games/gameThemeEditorHost.ts
const renameFromSlug = isNewTheme ? "" : startingSlug;
// Default the Save button to wherever the theme already lives: a collection theme defaults to
// "Save to Collection"; a factory theme to source; otherwise (book/new) to "Save to Book".
const themeSource = isNewTheme ? "none" : host.getThemeSource();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

[Devin] Investigate: Collection theme has no primary Save button while Save-to-Collection is disabled

defaultTarget can still evaluate to "collection", but the Save to Collection button is commented out as "temporarily disabled". For a theme whose source is the collection, that leaves no highlighted default action at all: Save to Book renders with the non-primary outline variant, because defaultTarget === "book" is false.

Two consequences worth confirming are intended for now:

  1. No primary action. A user editing a collection theme sees only outline buttons, so nothing indicates the expected action.
  2. Silent duplication. Saving to the book writes the theme there while the collection copy stays on disk, so the same slug ends up defined in both places. (Related to, but distinct from, the rename-orphan thread above.)

I confirmed the button is commented out and that defaultTarget is still allowed to be "collection", so both follow. Not a crash, and not fixed here — the right resolution depends on why collection-save is disabled, which is a call for the developer. Raised in the preflight decision report.

@hatton

hatton commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

[Claude Opus 5] Consulted Devin again on 2026-07-27 (18:03 UTC) up to commit 3a7e8fb37all bugs now clear.

Devin marks all 5 bugs it raised across this run as fixed, and reports 0 unfixed bugs at this commit. Over the three reviews it raised 5 bugs and 7 investigate flags; 15 informational items were reviewed and none warranted a change.

Fixed and resolved this run: the useMountEffect convention, the undeclared @emotion/cache, Emotion styles leaking on every editor open/close, a stacked ternary, and the save guard that let a new theme silently overwrite the theme it was based on.

Assessed as not an issue and resolved: the cross-realm React root (the probe span is a cached singleton, and the mount target is deliberate and documented). Two flags were stale — they cite a vite.config.mts restriction removed in 8624b7e and an @emotion/cache declaration added in d979ffc.

Three threads are deliberately left open for the developer, all in the preflight decision report:

plus Greptile's P1 on translate="no", pending the decision on whether to make those labels translatable now.

CI is green. The bot fix/re-review loop reached this skill's 4-cycle cap, so the one new flag at this commit was posted rather than fixed.

@hatton hatton closed this Jul 28, 2026
@hatton
hatton deleted the game-theme-editor branch July 28, 2026 16:02
@hatton

hatton commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

[Claude Opus 5] Superseded by #8118 — closed by a branch rename, not abandoned.

This work was sharing BL-16323 with the game-theme colour tweaks that already shipped separately in #7985. It now has its own card, BL-16618, and the branch was renamed game-theme-editorBL-16618-game-theme-editor to match. GitHub closes a PR when its head branch is renamed, so the work continues in #8118 on the same commits.

The review history here is still the record: the Devin consultation log and the mirrored finding threads live on this PR. #8118 links back here and lists the four findings that were still open, so nothing is lost — but new review activity should go to #8118.

One of those four (the factory-theme contrast regression in gamesThemes.less) is resolved in #8118: that file has been reverted to master, restoring the #7985 contrast fixes.

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.

1 participant