The Pokémon Showdown client builds its entire reactive architecture on a lightweight observable system defined inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/smogon/pokemon-showdown-client/llms.txt
Use this file to discover all available pages before exploring further.
client-core.ts. Rather than adopting React’s immutable data paradigm or a third-party state library, PS uses mutable model objects that notify subscribers whenever they change — a deliberate choice that keeps the bundle small and lets the same models power both the Preact-based UI and the IE7-compatible replay viewer.
PSModel and PSSubscription
PSModel<T> is the observable base class. It holds a list of PSSubscription<T> objects and fans out values to them on every update() call.
PSSubscription<T> is returned by subscribe(). Hold onto it so you can call unsubscribe() when the component unmounts:
subscribeAndRun immediately invokes the listener with the optional value argument before returning the subscription. This is useful for initialising a view to the current state without writing the update logic twice.Basic subscription example
PSStreamModel
PSStreamModel<T> extends the observable pattern with a backlog: events emitted before any subscriber has attached are queued and replayed when the first subscriber arrives. Nullish values are never added to the backlog.
PSPrefs
PSPrefs extends PSStreamModel<string | null> and manages all user preferences stored in localStorage. When a preference changes, update() is called with the key name so listeners can react selectively.
Theme
'light' | 'dark' | 'system' — controls the CSS theme. 'system' follows the OS preference.GIF / Animation flags
nogif disables animated GIF sprites (workaround for a Chrome 64 bug). noanim disables all battle animations. bwgfx forces Gen 5 sprite style.Past-gen graphics
nopastgens forces all sprites to use modern artwork regardless of the battle’s generation.In-chat PMs
inchatpm controls whether private messages appear inline in the chat panel.Reacting to preference changes
BecausePSPrefs streams the key that changed, you can skip re-rendering when an unrelated preference is updated:
Changing a preference
The PS Global Singleton
PS is the top-level application model, exported from client-main.ts. It extends PSModel (no type parameter — it notifies on any layout or state change) and owns every major sub-model.
ServerInfo and PSConfig
TheServerInfo interface describes the server PS is currently connected to, and PSConfig is the compile-time configuration object:
Putting It All Together
Subscribe to a model
Call
model.subscribe(listener) or model.subscribeAndRun(listener) to receive updates. Store the returned PSSubscription for cleanup.Update the model
Mutate the model’s properties and call
update() (with or without a value) to fan out to all subscribers.Why not use React state or a flux store?
Why not use React state or a flux store?
PS’s model system predates the broad adoption of hooks and flux stores, and it has to work in the IE7-compatible replay viewer as well as the full Preact client.
PSStreamModel’s backlog feature also solves a specific problem: the connection may emit messages before the UI is ready, and those messages must not be lost. A plain Redux store would require middleware to replay actions — here it’s built into the base class.