SteamDeck UI is a controller-first interface for Retail World of Warcraft, built for Steam Deck.
Written in TypeScript and compiled to Lua with TypeScriptToLua.
Requires Node.js 24 and Yarn 4.6.0.
Install dependencies and build the addon:
yarn install
yarn buildRun yarn dev to recompile Lua as you edit. Run yarn build again to refresh the complete addon in dist/.
Generate updated WoW API declarations with yarn setup when needed.
- Build the addon with
yarn build. - Create a
SteamDeckUI-devfolder inside your Retail WoW installation's_retail_/Interface/AddOns/directory. - Copy the contents of
dist/into that folder.SteamDeckUI-dev.tocshould sit directly insideInterface/AddOns/SteamDeckUI-dev/. - Enable SteamDeckUI-dev in the character selection screen's AddOns menu, then log in. Use
/reloadafter copying an updated build while logged in.
Use a Steam Input layout that sends native gamepad inputs.
Outside combat, tap View / Select / Back (PADBACK) to select the next displayed quest objective, wrapping to the first. Hold it for 3 seconds to collapse or expand the objective tracker; releasing after a hold does not change the selected quest. Quest cycling includes campaign, regular, bonus, and world quests; achievement and scenario entries are skipped. B continues to cancel addon panels.
For a release build, run yarn build:release and copy the contents of dist/ into Interface/AddOns/SteamDeckUI/ instead.
yarn test # Run unit tests
yarn typecheck # Check TypeScript types
yarn lint # Check formatting and lint rules
yarn build # Compile and package the addonUse yarn test:watch to rerun tests as you edit. Test controller input and UI behaviour in WoW after installing the addon.
The first captured error each session automatically opens Errors; later errors do not reopen the window. /sdui debug also opens this tab directly. The list runs oldest to newest; the red divider marks errors captured since the previous visit. Select an error to view its complete message and stack trace, or select the details for copying. Returning from details preserves the list's viewed boundary; reopening the Errors tab loads a fresh snapshot and saves a new viewed timestamp.
SteamDeckUIErrors stores the latest 100 captured occurrences (including repeated errors), with an ID, Unix timestamp, message and stack trace. Older occurrences are discarded. Flood protection permits a burst of 10 captures and refills at 10 per second; excess errors increment suppressedCount and update lastSuppressedAt without generating stacks or invoking the previous error handler. The Errors tab shows the suppressed count. Capture starts when SteamDeckUI loads; errors from before its handler was installed cannot be recovered.
WoW writes SavedVariables on /reload or normal logout. The file is _retail_/WTF/Account/<account>/SavedVariables/SteamDeckUI-dev.lua for development installs, or SteamDeckUI.lua for release installs. Both the error history and regular configuration live in this addon file. Changes are in memory until WoW flushes them; a crash may lose recent errors.
After testing, /reload or log out, then run:
yarn debug:extract > /tmp/steamdeck-ui-debug.json
# Optional path for another account or installation:
yarn debug:extract "/path/to/SavedVariables/SteamDeckUI-dev.lua"
# Optional native taint log from another location:
yarn debug:extract "/path/to/SavedVariables/SteamDeckUI-dev.lua" "/path/to/Logs/taint.log"Stdout contains JSON only; failures go to stderr and exit nonzero. The exporter parses Lua data without executing it and includes SteamDeckUIErrors, SteamDeckUILogs, settings, source path and file modification time. It omits the large collection cache. Old saves without logs export SteamDeckUILogs: null.
SteamDeckUI currently enables detailed native Retail taint logging (taintLog=2) by default at startup. Toggle Enable taint logging in /sdui debug → Errors, or use /sdui taint on|off. A successful toggle is saved across reloads and logouts; disabling it stays disabled on the next startup. The checkbox and /sdui taint status read the actual CVar, so rejected changes are not shown as successful. Logging affects the whole UI. If the client rejects addon control, use /console taintLog 2 or /console taintLog 0 directly; console changes do not update SteamDeckUI's saved preference. Reload after enabling before reproducing an issue.
After reproducing, log out normally before exporting so WoW flushes both SavedVariables and its native log. /reload saves addon history, but native log writes are periodic and logout provides the final flush. Export before starting another test session. Native logs live at _retail_/Logs/taint.log; addons cannot read this file in game. See the taintLog reference for logging levels and flushing behavior. The Retail CVar APIs are declared in Blizzard's Blizzard_APIDocumentationGenerated/CVarDocumentation.lua.
The export's nativeTaintLog includes the newest 1 MiB at most, with a partial leading line removed, plus source, modification time, total/omitted byte counts and truncated. It infers the log location from the SavedVariables path's WTF ancestor, or accepts the explicit second argument above. Missing/unreadable logs and paths outside a WoW installation produce missing, unavailable or unknown-path status while preserving the SavedVariables export. The native log may contain older sessions; use its timestamps together with the exported error timestamps and build identity. Existing ADDON_ACTION_BLOCKED/ADDON_ACTION_FORBIDDEN breadcrumbs remain separate from this file.
SteamDeckUILogs retains up to 10,000 log entries and 2,000,000 characters across reloads, with a droppedCount for evicted entries. It records application event names before dispatch, panel open/close requests, panel selection, session start/stop and existing scan/performance logs. Event payloads are excluded. This is rolling history; a busy hour may exceed the limit. The live Logs tab keeps its smaller session buffer.
Each error also stores up to 12,000 characters of preceding logs in context, preserving breadcrumbs even after the rolling log evicts them. Its environment snapshot includes instance name/type/ID/difficulty and capacity, delve progress/tier, group size, party/raid status, zone/subzone/map ID, class/level/spec/role, combat/rest/death/mount/flight state, game build/interface version, locale, FPS and latency. Unavailable or secret values are omitted and listed in unavailableFields; context collection does not scan inventory or units.
Every log line and error environment includes the short Git commit embedded at build time, suffixed with -dirty if the checkout had local changes. Run yarn build to refresh this identity along with the installed addon. Error flood protection still applies; suppressed occurrences have no individual snapshot. These exports provide evidence for debugging, but do not capture errors from before startup or guarantee that every bug raises a Lua error.
See LICENSE. Third-party asset credits are listed in assets/README.md.