verekia-stores
SKILL.md
Zustand Stores
Use Zustand stores for state that doesn't belong in the ECS. Each store has a consistent API pattern with use*, get*, set*, and reset* exports.
Store Types
- core-store: Global reactive state that doesn't fit in ECS (room metadata, connection status)
- ui-store: UI state like modals, panels, debug overlays
- local-store: User preferences persisted to localStorage
Core Store
For global reactive state that doesn't fit in ECS:
// stores/core-store.ts
import { create } from 'zustand'
const defaultState: {
isDebugMode: false
}
type State = typeof defaultState
type Key = keyof State
const useCoreStore = create<State>(() => structuredClone(defaultState))
export const useCore = <K extends Key>(key: K) => useCoreStore(state => state[key])
export const getCore = useCoreStore.getState
export const setCore = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
useCoreStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetCore = () => useCoreStore.setState(structuredClone(defaultState))
// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getCore = getCore
UI Store
For UI state like modals and debug info:
// stores/ui-store.ts
import { create } from 'zustand'
const defaultState = {
areSettingsOpen: false,
}
type State = typeof defaultState
type Key = keyof State
export type UIState = State
export type UIKey = Key
const useUIStore = create<State>(() => structuredClone(defaultState))
export const useUI = <K extends Key>(key: K) => useUIStore(state => state[key])
export const getUI = useUIStore.getState
export const setUI = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
useUIStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetUI = () => setUI(structuredClone(defaultState))
export const isAnyModalOpen = () => {
const ui = getUI()
return ui.areSettingsOpen
}
export const closeAnyModal = () => {
if (getUI().areSettingsOpen) {
setUI('areSettingsOpen', false)
return true
}
return false
}
export const useIsAnyModalOpen = () => {
const areSettingsOpen = useUI('areSettingsOpen')
return areSettingsOpen
}
// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getUI = getUI
Local Store (Persisted)
For user preferences synced with localStorage:
// stores/local-store.ts
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
const defaultState = {
hello: 'world',
}
type State = typeof defaultState
type Key = keyof State
const useLocalStore = create<State>()(persist(() => structuredClone(defaultState), { name: 'my-game-local' }))
export const useLocal = <K extends Key>(key: K) => useLocalStore(state => state[key])
export const getLocal = useLocalStore.getState
export const setLocal = <K extends Key>(...args: [key: K, value: State[K]] | [state: Partial<State>]) =>
useLocalStore.setState(args.length === 2 ? { [args[0]]: args[1] } : args[0])
export const resetLocal = () => setLocal(structuredClone(defaultState))
// @ts-expect-error Normal
if (typeof window !== 'undefined') window.getLocal = getLocal
Usage
// In React components (reactive)
const areSettingsOpen = useUI('areSettingsOpen')
// Outside React / in systems (non-reactive)
const settings = getUI().areSettingsOpen
// Setting values
setUI('areSettingsOpen', true)
setUI({ areSettingsOpen: true, debug: { drawCalls: 100 } })
// Reset to defaults
resetUI()
Key Concepts
use*hooks for reactive access in React componentsget*for non-reactive access in systems or callbacksset*supports both single key-value and partial state updatesreset*restores default state- Attach
get*towindowfor debugging in browser console - Use
structuredClone(defaultState)to avoid mutation issues
This skill is part of verekia's r3f-gamedev.
Weekly Installs
2
Repository
verekia/r3f-gamedevGitHub Stars
26
First Seen
Jan 21, 2026
Installed on
claude-code2