Skip to content

feat: retire the old Manifold themes, promote Royal into the Manifold name - #910

Closed
svenmalvik wants to merge 2 commits into
mainfrom
default-first-run-theme-royal-dark
Closed

feat: retire the old Manifold themes, promote Royal into the Manifold name#910
svenmalvik wants to merge 2 commits into
mainfrom
default-first-run-theme-royal-dark

Conversation

@svenmalvik

@svenmalvik svenmalvik commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Retires the original Manifold Dark/Light and renames the Royal pair into their place. The shipped set goes from six pairs to five, and a first run now opens on the deep navy/gold palette — under the Manifold name.

The theme JSONs carry no internal name field (the label comes purely from the filename map in theme-data.ts), so this is a file move plus a barrel edit. DEFAULT_SETTINGS.theme is manifold-dark, which is what SettingsStore.loadFromDisk() returns when ~/.manifold/config.json doesn't exist yet.

Migration

migrateLegacyTheme() maps saved royal-dark/royal-light to manifold-dark/manifold-light. This is load-bearing for royal-light: without it that id falls through to loadTheme()'s unknown-id fallback, which is dark, silently flipping a light-theme user to dark on upgrade.

Worth a reviewer's explicit sign-off: anyone who currently has the old manifold-dark/manifold-light selected keeps that id and will see the new palette after upgrading. That's inherent to retiring the old themes — those colors no longer ship anywhere — but it is a visible change for existing users who never opted into Royal.

Not changed

  • window-factory.ts:57 settings.theme ?? 'dracula' — a stale fallback for the pre-paint window background, unreachable via SettingsStore.
  • theme.css:73-118 — CSS-var fallbacks still commented as "match the default Dracula theme"; overwritten by applyThemeCssVars() once App mounts. A first launch does briefly paint these before the theme lands.
  • migrateLegacyTheme() still maps the legacy 'light'/'vs' values to a dark default (pre-existing, untouched).

Testing

  • npm test — 374 files / 2916 tests pass.
  • npm run typecheck — clean across web, node, and plugins.
  • Drove the built app under Playwright with an isolated HOME + CFFIXED_USER_HOME for a genuine first run (no config.json, and app.getPath('home') asserted to be the scratch dir so the real profile stayed untouched). Renderer resolved --bg-primary: #06080F, --bg-sidebar: #090D18, --accent: #E2C275, and the fresh config persisted theme: manifold-dark.
  • Rendered a component under manifold-light to confirm the light variant is the cream/navy former Royal Light.

New coverage in registry.test.ts: the default is Manifold Dark and a registered id; manifold-dark/manifold-light resolve to the Royal palette (#06080F / #F6F1E7); the royal-* ids are gone from the picker; and both migrate to the Manifold id of the same type, with royal-light asserted to stay light. settings-store.test.ts pins the fresh-install theme.

Test ids referencing removed themes were repointed: loadThemeVars cases to manifold-dark (it rejects unknown ids), parseArgs cases to jade-dark (any real non-default id proves parsing), and three fixture header comments to --theme manifold-dark so the documented command still runs.

🤖 Generated with Claude Code

A fresh install now starts on Royal Dark instead of Manifold Dark.
`DEFAULT_SETTINGS.theme` is what `SettingsStore.loadFromDisk()` returns when
`~/.manifold/config.json` does not exist yet, so this only affects first-time
users — an existing config's theme is merged over the defaults and is left
alone.

Left deliberately unchanged: `DEFAULT_THEME` in `themes/registry.ts` is the
fallback for an unresolvable theme id and the target of `migrateLegacyTheme()`
for old 'dark'/'light' values, which is an upgrade path rather than the
first-run default.

The registry test also pins that the default is a *registered* theme id:
`loadTheme()` silently falls back to manifold-dark for an unknown id, so a typo
in the default would otherwise ship the old theme with nothing failing.

`SettingsModal.test.tsx` restated the default theme in an assertion about a
modal rendered from `DEFAULT_SETTINGS`; since that test covers Save round-
tripping settings unchanged, it now reads the value from `DEFAULT_SETTINGS`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@svenmalvik
svenmalvik requested a review from a team August 8, 2026 16:07
… name

Deletes the original Manifold Dark/Light and renames the Royal pair into their
place, so the shipped set is five pairs and the default is the deep
navy/gold palette under the Manifold name. Supersedes the previous commit's
`royal-dark` default.

The theme JSONs carry no internal name field — the label comes purely from the
filename map in theme-data.ts — so this is a file move plus a barrel edit.

Migration: `migrateLegacyTheme()` maps saved `royal-dark`/`royal-light` ids to
`manifold-dark`/`manifold-light`. This is load-bearing for `royal-light`:
without it that id falls through to `loadTheme()`'s unknown-id fallback, which
is dark, silently flipping a light-theme user to dark on upgrade.

Anyone who had the old `manifold-dark`/`manifold-light` selected keeps that id
and now sees the new palette. That is inherent to retiring the old themes —
the previous colors no longer ship.

Test ids that referenced the removed themes were repointed: the screenshot
script's `loadThemeVars` cases to `manifold-dark` (it rejects unknown ids), its
`parseArgs` cases to `jade-dark` (any real non-default id proves parsing), and
the three fixture header comments to `--theme manifold-dark` so the documented
command still runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@svenmalvik svenmalvik closed this Aug 8, 2026
@svenmalvik
svenmalvik deleted the default-first-run-theme-royal-dark branch August 8, 2026 16:19
@svenmalvik svenmalvik changed the title feat: open a first run on the Royal Dark theme feat: retire the old Manifold themes, promote Royal into the Manifold name Aug 8, 2026
@svenmalvik

Copy link
Copy Markdown
Collaborator Author

Superseded by #913 — GitHub auto-closed this when the head branch was renamed to match the final change (the Royal themes are now the Manifold ones, so default-first-run-theme-royal-dark no longer described the work).

svenmalvik added a commit that referenced this pull request Aug 8, 2026
… name (#913)

## Summary

Retires the original **Manifold Dark/Light** and renames the **Royal**
pair into their place. The shipped set goes from six pairs to five, and
a first run now opens on the deep navy/gold palette — under the Manifold
name. Also clears out the Dracula-era leftovers the rename exposed.

The theme JSONs carry no internal `name` field (the label comes purely
from the filename map in `theme-data.ts`), so the rename itself is a
file move plus a barrel edit.

Note that **`defaults.ts` is untouched** — `DEFAULT_SETTINGS.theme` was
already `manifold-dark` and still is. What changed is the palette that
id resolves to. The new-default requirement is satisfied entirely by the
rename.

### Migration

`migrateLegacyTheme()` maps saved `royal-dark`/`royal-light` to
`manifold-dark`/`manifold-light`. This is load-bearing for
`royal-light`: without it that id falls through to `loadTheme()`'s
unknown-id fallback, which is **dark**, silently flipping a light-theme
user to dark on upgrade.

**Worth a reviewer's explicit sign-off:** anyone who currently has the
old `manifold-dark`/`manifold-light` selected keeps that id and will see
the *new* palette after upgrading. That's inherent to retiring the old
themes — those colors no longer ship anywhere — but it is a visible
change for existing users who never opted into Royal.

### Dracula cleanup

Two places still described a theme Manifold hasn't shipped in a long
time:

- `window-factory.ts` fell back to the literal id `'dracula'` for the
window's pre-paint background. Unreachable through `SettingsStore` (the
defaults always supply a theme), but it named a theme that no longer
exists, so the fallback would have dropped into `loadTheme()`'s catch.
Now uses the exported `DEFAULT_THEME`.
- `theme.css`'s `:root` block held Dracula's palette as the pre-JS
fallback. Those values are what paints between the window's first frame
and App mounting, so they were **a real flash of grey-purple** before
the theme landed — driving the built app showed pre-mount `--bg-primary:
#282a36` against an applied `#06080F`. Both now read `#06080F`.

Repointing the obvious block surfaced four more strays that the new
drift test caught: `--sidebar-active-border` and `--accent-subtle` still
carried the old `#007acc` accent blue, and
`--control-bg-hover`/`--statusbar-hover-bg` had drifted to generic white
overlays.

`theme-css-fallbacks.test.ts` pins the colour fallbacks against the
default theme's converted vars so this can't rot again. **Shadows are
deliberately excluded** — `theme.css` layers an extra `inset 0 1px 0
rgba(255,255,255,…)` top highlight onto each that the adapter doesn't
emit. That reads as a stylesheet design choice rather than palette
drift, and pinning it would force the richer shadow to be dropped. Happy
to reconcile them either direction if you'd rather they matched.

### Still not changed

`migrateLegacyTheme()` maps the legacy `'light'`/`'vs'` values to a
*dark* default (pre-existing, untouched).

## Testing

- `npm test` — 376 files / 2923 tests pass.
- `npm run typecheck` — clean across web, node, and plugins.
- Drove the **built** app under Playwright with an isolated `HOME` +
`CFFIXED_USER_HOME` for a genuine first run (no `config.json`, and
`app.getPath('home')` asserted to be the scratch dir so the real profile
stayed untouched). Pre-mount fallback `#06080f`, applied `--bg-primary:
#06080F`, `--bg-sidebar: #090D18`, `--accent: #E2C275`, and the fresh
config persisted `theme: manifold-dark`.
- Rendered a component under `manifold-light` to confirm the light
variant is the cream/navy former Royal Light.

New coverage in `registry.test.ts`: the default is Manifold Dark *and* a
registered id; `manifold-dark`/`manifold-light` resolve to the Royal
palette (`#06080F` / `#F6F1E7`) — this is what would fail if the rename
regressed, since the id itself never changed; the `royal-*` ids are gone
from the picker; and both migrate to the Manifold id **of the same
type**, with `royal-light` asserted to stay light.
`settings-store.test.ts` pins the fresh-install theme.

Test ids referencing removed themes were repointed: `loadThemeVars`
cases to `manifold-dark` (it rejects unknown ids), `parseArgs` cases to
`jade-dark` (any real non-default id proves parsing), and three fixture
header comments to `--theme manifold-dark` so the documented command
still runs.

Rebased onto `main` after #909/#911/#912 landed. Supersedes #910, which
GitHub auto-closed when its head branch was renamed to match the final
change.

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

---------

Co-authored-by: Claude Opus 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.

1 participant