Skip to content

Add localStorage persistence for UI state#56

Merged
ajbtech merged 2 commits into
mainfrom
claude/trusting-keller-foGP4
May 29, 2026
Merged

Add localStorage persistence for UI state#56
ajbtech merged 2 commits into
mainfrom
claude/trusting-keller-foGP4

Conversation

@ajbtech

@ajbtech ajbtech commented May 29, 2026

Copy link
Copy Markdown
Owner

Summary

Adds localStorage persistence so users' party composition and encounter settings are automatically saved and restored across sessions. Introduces a pure persist.js module that handles serialization/deserialization with strict validation to prevent stale or hand-edited snapshots from corrupting the engine state.

Type of change

  • New feature
  • Bug fix
  • Data/formula correction
  • Docs / tooling

Implementation details

New module: src/persist.js

  • defaultState() — factory for the canonical initial state
  • serialize(state) — converts UI state to JSON-safe snapshot
  • deserialize(raw) — rehydrates from storage with validation:
    • Drops non-canonical race/class values (via isRace/isClass checks)
    • Clamps numeric fields to valid ranges (levels 1–60, mob level 1–70, etc.)
    • Rounds floats and rejects non-finite numbers
    • Pads/truncates party arrays to exactly 6 members
    • Falls back to defaultState() on null/undefined/garbage input
  • STORAGE_KEY — versioned string ("eq-xp-calculator/v1") for localStorage

Changes to src/ui.js

  • Replaced inline state initialization with defaultState()
  • Added loadFromStorage() — pulls snapshot on page load (before DOM build) with graceful fallback if localStorage is disabled or corrupted
  • Added saveToStorage() — writes serialized state after every refresh() with best-effort error handling
  • Minor: added patch date note to class XP penalties label

Documentation: architecture.md

  • Added persist.js to the module breakdown with description of its role

Validation approach

The deserialize() function is defensive: it validates every field independently and falls back to defaults for any invalid data. This ensures a stale snapshot (e.g., from a previous version) or hand-edited JSON blob can never inject a non-canonical race/class or out-of-range number into the engine.

Checklist

  • Added comprehensive unit tests for serialization, deserialization, validation, and edge cases (test/persist.test.js)
  • npm test passes (185 lines of golden-value tests covering all validation paths)
  • npm run lint passes
  • npm run format:check passes
  • src/xp.js remains pure (no DOM access)

https://claude.ai/code/session_019NDndqSRkT7BonKsEGXxfL

claude added 2 commits May 29, 2026 18:47
Adds a pure src/persist.js module (serialize / deserialize / defaultState /
versioned STORAGE_KEY) covered by golden-value tests, and wires src/ui.js
to read the last snapshot on start and rewrite it after every refresh.
Deserialize validates every field against the canonical enums and ranges,
so a stale or hand-edited blob is dropped to defaults rather than poisoning
the engine. localStorage I/O is wrapped in try/catch so private-mode and
quota errors degrade silently.

https://claude.ai/code/session_019NDndqSRkT7BonKsEGXxfL
Adds "(Jan 14, 2001 patch)" as a faint subtitle next to the toggle so
players know exactly which era flipping it switches between.

https://claude.ai/code/session_019NDndqSRkT7BonKsEGXxfL
@ajbtech ajbtech merged commit 2e4420d into main May 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants