feat(mascot): load Human mascots from GitHub manifest (#4312)

This commit is contained in:
Steven Enamakel
2026-06-29 20:46:20 -07:00
committed by GitHub
parent 89be906d20
commit d746fec3ef
43 changed files with 2367 additions and 217 deletions
+5 -4
View File
@@ -159,13 +159,14 @@ const persistedThreadReducer = persistReducer(threadPersistConfig, threadReducer
const layoutPersistConfig = { key: 'layout', storage, whitelist: ['panels'] };
const persistedLayoutReducer = persistReducer(layoutPersistConfig, layoutReducer);
// Persist only previously persisted mascot appearance fields plus the custom
// GIF override added by this feature; leave existing non-persisted mascot
// fields as runtime state to avoid changing refresh behavior.
// Persist the mascot appearance fields, the custom GIF override, and the
// selected mascot id (so the chosen GitHub-manifest mascot survives a reload —
// the slice's REHYDRATE guard re-validates it). Other mascot fields stay as
// runtime state.
const mascotPersistConfig = {
key: 'mascot',
storage,
whitelist: ['color', 'voiceId', 'customMascotGifUrl'],
whitelist: ['color', 'voiceId', 'customMascotGifUrl', 'selectedMascotId'],
};
const persistedMascotReducer = persistReducer(mascotPersistConfig, mascotReducer);
+6 -6
View File
@@ -110,12 +110,12 @@ export interface MascotState {
*/
voiceUseLocaleDefault: boolean;
/**
* Server-side mascot id selected from the backend mascot library
* (PR tinyhumansai/backend#770). `null` keeps the local YellowMascot
* renderer; any non-empty value tells `BackendMascot` (loaded via
* `mascotService`) to take over. The id is opaque server-side and
* length-capped at the same threshold as voiceId to keep the
* persisted blob bounded.
* Mascot id selected from the published GitHub manifest
* (`tinyhumansai/mascots`, resolved via `useMascotManifest`). `null` falls
* back to the manifest's default (first `ready`) mascot; any non-empty value
* pins that specific mascot. The id is the manifest entry id (e.g.
* `tiny-mascot`) and length-capped at the same threshold as voiceId to keep
* the persisted blob bounded.
*/
selectedMascotId: string | null;
/**