* feat: add draggable sidebar resizer
- Add resizer handle between map and event panel
- Sidebar width adjustable from 300px to 50% screen width
- Default width remains 400px
- Auto-adjust on window resize
* fix: preserve map zoom when resizing sidebar
Only update viewport screen size without re-fitting the map
* fix: use window size for canvas to prevent map scaling on resize
- Canvas size now based on window instead of container
- Sidebar resize only clips the visible area, map stays same size
- Remove CSS stretch on canvas element
* docs: update sidebar-resizer spec with canvas fix
The pause indicator was showing 'paused' while the game was still running
because isManualPaused was being modified by both user actions (clicking
pause button) and system actions (opening menu).
Changes:
- systemStore: pause()/resume() no longer modify isManualPaused, only
togglePause() does (with optimistic update + rollback on failure)
- useGameControl: consolidate 3 overlapping watches into 1 clean watch
that only handles menu open/close without polluting manual pause state
- App.vue: explicitly call resumeGame() API when game initializes
Add splash layer, support game start, settings, exit
Modify settings layer, add "go back to splash" and "exit"
Add character threshold for history input
Closes#28
- Add async initialization with 6 phases: scanning_assets, loading_map,
initializing_sects, generating_avatars, checking_llm, generating_initial_events
- Add /api/init-status endpoint for frontend polling
- Add /api/control/reinit endpoint for error recovery
- Add LoadingOverlay.vue component with:
- Progress ring with gradient
- Phase text in xianxia style (rotating messages for LLM phase)
- Tips that rotate every 5 seconds
- Time-based background transparency (fades to 80% over 20s)
- Backdrop blur effect
- Error state with retry button
- Preload map and avatars during LLM initialization for smoother UX
- Add comprehensive tests for init status API
Problem:
When loading a save (e.g., from year 106), events from year 100 would appear.
This happened because the game auto-started on server startup and client
connection, generating initialization events before the user could load a save.
Solution:
1. Backend: Keep game paused on startup even if LLM check passes
2. Backend: Remove auto-resume on first WebSocket connection
3. Frontend: Start with game paused (isManualPaused = true)
Now the user must explicitly click 'resume' to start a new game, or load a
save first. This prevents the race condition where game_loop generates events
with stale world state.