// Det. Hale — your partner on the wire. Contextual, spoiler-safe hints from the server. import { useEffect, useState } from 'preact/hooks' import { getHint } from '../api' import { useTypewriter } from '../engine/pixel' import { useGame } from '../store' import { Portrait } from './components' const HIDDEN = new Set(['title', 'verdict', 'share', 'boot']) const FALLBACK = 'Work the evidence, detective. Find where a statement and a fact disagree, and press there.' export function Assistant() { const g = useGame() const [open, setOpen] = useState(false) const [hint, setHint] = useState('') const screen = g.state.screen useEffect(() => { const t = () => setOpen((o) => !o) const c = () => setOpen(false) window.addEventListener('toggle-hint', t) window.addEventListener('close-hint', c) return () => { window.removeEventListener('toggle-hint', t) window.removeEventListener('close-hint', c) } }, []) useEffect(() => { setOpen(false) }, [screen]) useEffect(() => { if (!open) return let alive = true setHint('') getHint(g.runId, screen) .then((r) => { if (alive) setHint(r.hint || FALLBACK) }) .catch(() => { if (alive) setHint(FALLBACK) }) return () => { alive = false } }, [open, screen, g.runId]) const [typed, done] = useTypewriter(open ? hint : '', g.state.tweaks.typeSpeed || 18, open) if (HIDDEN.has(screen) || !open) return null return (
“{typed} {!done && }”