feat(settings): add mascot color customization (closes #1651)#1667
Merged
senamakel merged 1 commit intoMay 13, 2026
Merged
Conversation
) Adds a "Mascot" entry under Settings → General with five preset color swatches (yellow, burgundy, black, navy, green). The selection lives in a new Redux slice persisted through `userScopedStorage`, so it survives restarts and is per-user. Existing users keep yellow until they change it, and unknown persisted values fall back to the default on rehydrate. HumanPage and the Meet camera frame producer both consume the selected color so the mascot stays consistent wherever it renders.
Contributor
📝 WalkthroughWalkthroughThis pull request implements mascot color customization, allowing users to select from preset color variants in Settings. The changes add Redux state management with persistence, a new settings panel UI, and integrate the selected color into all mascot renderings throughout the app. ChangesMascot Color Customization
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mascotSlicepersists the chosen color throughuserScopedStorage(per-user, survives restarts) and falls back to the default on rehydrate when the persisted value is missing or unknown.HumanPageand the Meet camera frame producer both read the color from Redux so the mascot stays consistent wherever it renders.Problem
Closes #1651. The app shipped multiple mascot color variants (already wired through
mascotPalette.ts) but no product UI for users to pick one — making the experience feel fixed and impersonal. There was also no settings surface or persistence path that future customization work (accessories, style packs, etc.) could build on.Solution
app/src/store/mascotSlice.tswith aMascotColorselector,setMascotColoraction, validation guard, andREHYDRATEhandling that defaults unknown variants back to yellow.userScopedStorage(whitelist:color), keyed asmascotso each user's preference is namespaced.MascotPanelwith a 5-swatch radiogroup, accessible roles/labels, and a graceful empty-state for builds with no available variants. Reachable from Settings home (General → Mascot) and the new/settings/mascotroute.HumanPageandMascotFrameProducernow derivemascotColorfromselectMascotColorinstead of hardcoding'yellow'. The native macOS mascot NSPanel webview (MascotWindowApp) is intentionally untouched — it runs outside the Redux store and is a separate follow-up.Submission Checklist
mascotSlice.test.tsandMascotPanel.test.tsx; integration sites (HumanPage / MascotFrameProducer) are one-line selector reads.docs/TEST-COVERAGE-MATRIX.md— coverage matrix update deferred to a follow-up that bundles broader settings rows. (Coverage matrix updated)Closes #1651in the## Relatedsection.Impact
userScopedStorageredux-persist path, so logout/login carries the preference per the same rules as notifications/threads/etc.yellowdefault until they change it; unknown persisted values are coerced back to the default.Related
MascotWindowApp) and extend customization beyond color (accessories, expressions, style packs).AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
Validation Run
pnpm --filter openhuman-app format:check(ranpnpm formatwhich is a superset; output clean)pnpm typecheckpnpm vitest run --config test/vitest.config.ts src/store/__tests__/mascotSlice.test.ts src/components/settings/panels/__tests__/MascotPanel.test.tsx(15/15 passed)Validation Blocked
Behavior Changes
/settings/mascotpanel with five color swatches; selecting one updates the mascot immediately on HumanPage and in the Meet camera frame.Parity Contract
<YellowMascot>is unchanged (already acceptedmascotColor).setMascotColorignores unknown variants — so older persisted state never crashes a future build that dropped a variant.Duplicate / Superseded PR Handling
Summary by CodeRabbit