Some people find the drifting ambient petals distracting rather than cozy, so make the whole PetalFall layer opt-out-able from a 🌸 toggle sitting just left of the sound toggle in the status bar. Mirrors the existing sound-mute pattern: a tiny localStorage-backed pub/sub (effects/petals.ts) drives a PetalsToggle twin of SoundToggle. PetalFall subscribes to the setting, stops animating and wipes the canvas when off, and the choice persists across reloads. Works in both day (petals) and night (stars) modes. Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
37 lines
1015 B
TypeScript
37 lines
1015 B
TypeScript
// The on/off preference for the ambient falling-petals layer (PetalFall). Some
|
|
// people find drifting petals distracting rather than cozy, so the whole effect
|
|
// is opt-out-able and the choice persists in localStorage so it survives reloads.
|
|
// Mirrors the tiny pub/sub used for the sound mute toggle (../audio/sounds).
|
|
|
|
const STORAGE_KEY = 'petal.petals'
|
|
|
|
let enabled = readEnabled()
|
|
const listeners = new Set<(on: boolean) => void>()
|
|
|
|
function readEnabled(): boolean {
|
|
try {
|
|
return localStorage.getItem(STORAGE_KEY) !== 'off'
|
|
} catch {
|
|
return true
|
|
}
|
|
}
|
|
|
|
export function isPetalsEnabled(): boolean {
|
|
return enabled
|
|
}
|
|
|
|
export function setPetalsEnabled(on: boolean): void {
|
|
enabled = on
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, on ? 'on' : 'off')
|
|
} catch {
|
|
/* private mode — choice just won't persist */
|
|
}
|
|
listeners.forEach((fn) => fn(on))
|
|
}
|
|
|
|
export function onPetalsEnabledChange(fn: (on: boolean) => void): () => void {
|
|
listeners.add(fn)
|
|
return () => listeners.delete(fn)
|
|
}
|