Spaces:
Running
Running
| import type { BubbleStyle, SpriteForm } from "../ui/Sprite"; | |
| import { DEFAULT_KOKORO_VOICE, type VoiceEngine, type VoiceMode } from "./voice"; | |
| export type Theme = "terrarium" | "candlelight" | "nocturne"; | |
| export type NotifyStyle = "adaptive" | "bubble" | "toast" | "interrupt"; | |
| // off: never. ondemand: only the "Look around" button. ambient: auto, on a slow | |
| // timer, paused when idle/hidden so the cloud GPU scales to zero (cost-safe). | |
| export type VisionMode = "off" | "ondemand" | "ambient"; | |
| /** Ambient capture interval. Doesn't change cloud cost much (GPU stays warm | |
| * while active regardless) β idle-off is the real saving β but a slower cadence | |
| * is gentler and plenty for a screen that changes on human timescales. */ | |
| export const AMBIENT_INTERVAL_MS = 45_000; | |
| export interface Settings { | |
| theme: Theme; | |
| accent: string; | |
| form: SpriteForm; | |
| /** 0..100 β how often Puck wanders and how dense events are. */ | |
| presence: number; | |
| mischief: number; | |
| /** Comment typography: fairy serif, plain UI, or handwriting. */ | |
| voice: BubbleStyle; | |
| voiceSound: VoiceMode; | |
| /** Which TTS engine: local neural (Kokoro) or the OS voices. */ | |
| voiceEngine: VoiceEngine; | |
| /** Chosen OS (speechSynthesis) voice name; "" = auto-pick a soft english voice. */ | |
| voiceName: string; | |
| /** Chosen Kokoro voice id (e.g. "af_heart", "am_puck"). */ | |
| kokoroVoice: string; | |
| /** Chosen macOS `say` voice name (e.g. "Samantha"); "" = system default. */ | |
| sayVoice: string; | |
| /** Speak the short reaction shouts ("NANI?!", "shipped!") aloud too. */ | |
| speakShouts: boolean; | |
| notify: NotifyStyle; | |
| /** Mirror surfaced comments to OS notifications when the tab is hidden. */ | |
| osNotify: boolean; | |
| /** How Puck uses his eyes (vision). Default on-demand: nothing runs unattended. */ | |
| visionMode: VisionMode; | |
| } | |
| export const ACCENTS = ["#e7b85c", "#8fcf86", "#e58fa6", "#b89be6", "#6fc6d6"] as const; | |
| export const defaultSettings = (): Settings => ({ | |
| theme: "terrarium", | |
| accent: "#e7b85c", | |
| form: "mossling", | |
| presence: 62, | |
| mischief: 45, | |
| voice: "voice", | |
| voiceSound: "full", // audible by default (browser autoplay may need one click first) | |
| voiceEngine: "say", // Mac-native voice β works in the overlay and the browser demo alike | |
| voiceName: "", | |
| kokoroVoice: DEFAULT_KOKORO_VOICE, | |
| sayVoice: "Samantha", | |
| speakShouts: true, | |
| notify: "adaptive", | |
| osNotify: false, | |
| visionMode: "ondemand", | |
| }); | |
| /** Readable ink color for text on top of the accent. */ | |
| export function inkFor(hex: string): string { | |
| const h = hex.replace("#", ""); | |
| const n = parseInt(h.length === 3 ? h.replace(/./g, (c) => c + c) : h, 16); | |
| const r = (n >> 16) & 255; | |
| const g = (n >> 8) & 255; | |
| const b = n & 255; | |
| return r * 299 + g * 587 + b * 114 > 150000 ? "#22180a" : "#fff7e8"; | |
| } | |