fuzzyworld

nuts / files / src / persistence.ts

persistence.ts

Blame: the commit that last changed each line · file · history

aa6e5a99 2026-04-13 Pavel Safronov1const DATA_VERSION = 3
f1262fd9 2026-04-12 Pavel Safronov2
3const KEYS = {
aa6e5a99 2026-04-13 Pavel Safronov4 settings: 'nuts-settings-v3',
5 snapshot: 'nuts-snapshot-v3',
f1262fd9 2026-04-12 Pavel Safronov6} as const
7
8// ── Settings ───────────────────────────────────────────────────────────────
9
10export interface PersistedSettings {
11 v: number
12 nutRadius: number
937f9abc 2026-04-12 Pavel Safronov13 gravityMode?: string
14 vibrateEnabled?: boolean
98ba5504 2026-04-13 Pavel Safronov15 vibrateItems?: boolean
16 vibrateEdges?: boolean
74d506c6 2026-04-12 Pavel Safronov17 kind?: string
98ba5504 2026-04-13 Pavel Safronov18 randomPool?: string[]
aa6e5a99 2026-04-13 Pavel Safronov19 refill?: boolean
f1262fd9 2026-04-12 Pavel Safronov20}
21
22export function loadSettings(): PersistedSettings | null {
23 try {
24 const raw = localStorage.getItem(KEYS.settings)
25 if (!raw) return null
26 const parsed = JSON.parse(raw) as PersistedSettings
27 if (parsed.v !== DATA_VERSION) return null
28 return parsed
29 } catch {
30 return null
31 }
32}
33
34export function saveSettings(s: Omit<PersistedSettings, 'v'>): void {
35 try {
36 localStorage.setItem(KEYS.settings, JSON.stringify({ v: DATA_VERSION, ...s }))
37 } catch { /* storage full – ignore */ }
38}
39
40// ── Nut snapshot ───────────────────────────────────────────────────────────
41
42export interface NutSnapshot {
43 x: number // normalised 0..1 (relative to screen size)
44 y: number
45 angle: number
46 radius: number // absolute px
47 colorIndex: number
a2e3ea1a 2026-04-13 Pavel Safronov48 kind: 'nut' | 'gem' | 'balloon' | 'metalnut' | 'rock' | 'stressball' | 'coin'
f1262fd9 2026-04-12 Pavel Safronov49 gemVariant: number
50}
51
52export interface SnapshotRecord {
53 v: number
54 screenW: number
55 screenH: number
56 nuts: NutSnapshot[]
57}
58
59export function saveSnapshot(
a2e3ea1a 2026-04-13 Pavel Safronov60 nuts: Array<{ body: { position: { x: number; y: number }; angle: number }; radius: number; colorIndex: number; kind: 'nut' | 'gem' | 'balloon' | 'metalnut' | 'rock' | 'stressball' | 'coin'; gemVariant: number }>,
f1262fd9 2026-04-12 Pavel Safronov61 screenW: number,
62 screenH: number,
63): void {
64 try {
65 const record: SnapshotRecord = {
66 v: DATA_VERSION,
67 screenW,
68 screenH,
69 nuts: nuts.map(n => ({
70 x: n.body.position.x / screenW,
71 y: n.body.position.y / screenH,
72 angle: n.body.angle,
73 radius: n.radius,
74 colorIndex: n.colorIndex,
75 kind: n.kind,
76 gemVariant: n.gemVariant,
77 })),
78 }
79 localStorage.setItem(KEYS.snapshot, JSON.stringify(record))
80 } catch { /* storage full – ignore */ }
81}
82
83export function loadSnapshot(): SnapshotRecord | null {
84 try {
85 const raw = localStorage.getItem(KEYS.snapshot)
86 if (!raw) return null
87 const record = JSON.parse(raw) as SnapshotRecord
88 if (record.v !== DATA_VERSION) return null
89 return record
90 } catch {
91 return null
92 }
93}
94
95export function clearSnapshot(): void {
96 localStorage.removeItem(KEYS.snapshot)
97}