Add EMF field mode, Armory shop/waitlist, and ambient haunting layer
Three self-contained features, verified complete and cross-wired end-to-end (audited: backend 54/54 tests, frontend 110/110 tests, tsc --noEmit clean, i18n coverage script clean): - EMF mode: DeviceMotion/DeviceOrientation-based field-meter sensing, a fifth séance channel alongside Wire/EVP/Radio/Ouija, with its own fragment prompt persona and full frontend gauge UI. - Armory (shop/waitlist): pre-order capture page for the future Ultimate Quantum Box hardware line, rate-limited public endpoint, explicitly no payment collection. - Haunting layer: ambient possession effects (dread-bed audio, title glitching, idle-paced whispers/manifests), respects prefers-reduced-motion, mounted once at the app root. Plus WebUSB robustness fixes in lib/sdr.ts (Terratec vendor ID, explicit selectConfiguration, isSecureContext gate). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
This commit is contained in:
@@ -36,7 +36,7 @@ export type Utterance = {
|
||||
|
||||
export type AnomalyEntry = {
|
||||
id: number
|
||||
source: 'radio' | 'evp' | 'wire'
|
||||
source: 'radio' | 'evp' | 'wire' | 'emf'
|
||||
frequency: number
|
||||
magnitude: number
|
||||
at: number
|
||||
@@ -101,7 +101,7 @@ const TOAST_CAP = 4
|
||||
export type SeanceAction =
|
||||
| { type: 'connection'; state: VeilConnectionState }
|
||||
| { type: 'frame'; frame: ServerFrame; at?: number }
|
||||
| { type: 'local_anomaly'; source: 'radio' | 'evp' | 'wire'; frequency: number; magnitude: number; at?: number }
|
||||
| { type: 'local_anomaly'; source: 'radio' | 'evp' | 'wire' | 'emf'; frequency: number; magnitude: number; at?: number }
|
||||
| { type: 'local_question'; text: string; at?: number }
|
||||
| { type: 'set_mode'; mode: Mode }
|
||||
| { type: 'set_language'; language: Language }
|
||||
@@ -377,7 +377,7 @@ export type SeanceApi = {
|
||||
setLanguage: (language: Language) => void
|
||||
summon: () => void
|
||||
ask: (text: string) => void
|
||||
sendAnomaly: (source: 'radio' | 'evp' | 'wire', frequency: number, magnitude: number) => void
|
||||
sendAnomaly: (source: 'radio' | 'evp' | 'wire' | 'emf', frequency: number, magnitude: number) => void
|
||||
playUtterance: (utteranceId: string) => void
|
||||
dismissToast: (id: number) => void
|
||||
}
|
||||
@@ -450,7 +450,7 @@ export function SeanceProvider({ children }: { children: ReactNode }) {
|
||||
}, [])
|
||||
|
||||
const sendAnomaly = useCallback(
|
||||
(source: 'radio' | 'evp' | 'wire', frequency: number, magnitude: number) => {
|
||||
(source: 'radio' | 'evp' | 'wire' | 'emf', frequency: number, magnitude: number) => {
|
||||
dispatch({ type: 'local_anomaly', source, frequency, magnitude, at: Date.now() })
|
||||
socketRef.current?.send({ type: 'anomaly', source, frequency, magnitude })
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user