import type { SuixinBaseThemeId, SuixinThemeStateV1, UserProfileScoring } from '@/src/storage/appStorage'; import { getThemeTriplet, NEUTRAL_THEME_COLORS } from './palette'; import { lerpHex } from './colorMath'; import { computeTFromStep } from './progress'; import { pickSuixinBaseThemeId } from './pickTheme'; export { NEUTRAL_THEME_COLORS } from './palette'; export { pickSuixinBaseThemeId } from './pickTheme'; /** * 根据 base theme 与 step 计算当前背景纯色 */ export function computeSuixinSolidColor(args: { baseThemeId: SuixinBaseThemeId; stepIndex: number; seed: string; }): string { const [top, _mid, bottom] = getThemeTriplet(args.baseThemeId); const t = computeTFromStep({ stepIndex: args.stepIndex, segments: 12, seed: args.seed }); return lerpHex(top, bottom, t, NEUTRAL_THEME_COLORS[1]); } /** * 初始化一份随心状态(在冷启动会话内锁定 base theme) */ export function buildInitialSuixinState(args: { bootId: string; profile: UserProfileScoring | null; now?: Date; }): SuixinThemeStateV1 { const now = args.now ?? new Date(); const baseThemeId = pickSuixinBaseThemeId(args.profile); const seed = args.bootId; const step_index = 0; const last_color = computeSuixinSolidColor({ baseThemeId, stepIndex: step_index, seed }); return { schema_version: 1, saved_at: now.toISOString(), boot_id: args.bootId, base_theme_id: baseThemeId, seed, step_index, last_color, }; } /** * 切换文案时推进一步(不跨主题) */ export function advanceSuixinState(prev: SuixinThemeStateV1, now?: Date): SuixinThemeStateV1 { const nextStep = (Number.isFinite(prev.step_index) ? prev.step_index : 0) + 1; const last_color = computeSuixinSolidColor({ baseThemeId: prev.base_theme_id, stepIndex: nextStep, seed: prev.seed, }); return { ...prev, saved_at: (now ?? new Date()).toISOString(), step_index: nextStep, last_color, }; }