Architecture
Project Overview
WowVision is a World of Warcraft accessibility addon for visually impaired players. It provides TTS announcements, sound alerts, and audio-navigable buffers so players can access game state without a visual display.
Supports 5 game versions via separate TOC files: Vanilla, TBC, Mists, Retail, and WoW: Forever (client codename Camelot).
Directory Structure
WowVision/
├── core/ # Main framework (~1.1M) - shared by all versions
│ ├── ui/ # Virtual DOM UI framework
│ ├── info/ # InfoManager/InfoClass/Field system
│ ├── objects/ # Object tracking system
│ ├── alerts/ # Alert/notification system
│ ├── buffers/ # Information buffers (audio-browsable lists)
│ ├── monitors/ # Reactive alert system (monitors + rules)
│ ├── module/ # Module base class
│ ├── components/ # ComponentRegistry factory system
│ ├── navigation/ # Compass, maps, location
│ ├── chat/ # Chat handling
│ ├── windows/ # Window modules (game menu, merchant, mail, etc.)
│ ├── dataBinding/ # Two-way data binding
│ ├── audio/ # TTS and audio playback
│ └── *.lua # Core files (WowVision.lua, Event.lua, Registry.lua, etc.)
├── classic/ # Classic/Vanilla modules (shared by Vanilla, TBC, Mists)
├── tbc/ # TBC-specific modules
├── mists/ # Mists-specific modules
├── retail/ # Retail-specific modules
├── camelot/ # WoW: Forever-specific modules (loads after retail/)
├── audio/ # Git submodule: voice packs
├── locale/ # Git submodule: localization strings
├── libs/ # Ace3, middleclass, LibSharedMedia, LibRangeCheck
├── docs/ # mdBook documentation
└── *.toc # 5 TOC files (one per game version)
Loading Chain
Each TOC file defines the load order:
libs.xml— Ace3 libraries[version]/setup.lua— Version constants (e.g.,UI_DELAY)modules.xml— Core framework (all systems)[version]/modules.xml— Version-specific modules
| TOC File | Interface | Setup | Modules Loaded |
|---|---|---|---|
| WowVision_Vanilla.toc | 11507 | classic/setup.lua | classic/ |
| WowVision_TBC.toc | 20505 | classic/setup.lua | classic/ + tbc/ |
| WowVision_Mists.toc | 50500 | classic/setup.lua | classic/ + mists/ |
| WowVision_Standard.toc | 120005 | retail/setup.lua | retail/ |
| WowVision_Camelot.toc | 16001 | retail/setup.lua | retail/ + camelot/ |
TBC and Mists both load classic/ modules first, then layer their own on top. WoW: Forever runs on the modern engine with vanilla content, so its _Camelot TOC loads retail/ first and layers camelot/ on top. No runtime version checks — the TOC file selection handles everything.
OOP System
All classes use libs/middleclass.lua:
local MyClass = WowVision.Class("MyClass", ParentClass)
MyClass:include(SomeMixin)
function MyClass:initialize(...) end
local instance = MyClass:new(...)
Core Update Loop
WowVision:OnUpdate()
├── WowVision.objects:update() # Object type updates (unit GUIDs, cooldowns, etc.)
├── Module.runAllUpdates() # Monitor updates, buffer updates, etc.
└── UIHost:update() # UI reconciliation, navigation, input
objects:update() runs first so game state is fresh before monitors and UI process it.
Key Singletons
| Singleton | Purpose |
|---|---|
WowVision | Main addon (Ace3) |
WowVision.base | Root module |
WowVision.objects | Object type registry |
WowVision.ui | UI element type manager |
WowVision.info | Field type registry |
WowVision.dataBinding | Data binding factory |
WowVision.buffers | Buffer type registry |
WowVision.monitors | Monitor/rule registries |
WowVision.components | ComponentRegistry factory |
WowVision.alerts | Alert/output type registry |
WowVision.spellHistory | Spell cast history |
Event System
Simple pub/sub used throughout:
local event = WowVision.Event:new("myEvent")
event:subscribe(subscriber, function(self, eventName, ...) end)
event:emit(arg1, arg2, ...)
event:unsubscribe(subscriber)
Registry Pattern
Key-value store used for all type registries:
local reg = WowVision.Registry:new()
reg:register("key", value)
local item = reg:get("key")
-- reg.items = ordered array, reg.itemKeys = parallel key array
Database / Persistence
WoW SavedVariables store persistent data in WowVisionDB. On initialization:
WowVision:OnInitialize()reconciles saved data with default schemaWowVision.base:setDBObj(db)cascades DB binding through the module hierarchy- Each module, alert, and field gets linked to its DB section
- Field changes auto-persist via
obj.db[key] = valueinField:set()
Classes stored in ComponentArrays (like Rules, Monitors) need a setDB(db) method that cascades through self.class.info:setDB(self, db) to properly link nested fields like Alerts.
Version-Specific Differences
Speech API
- Classic/Mists:
C_VoiceChat.SpeakText(voiceID, text, destination, rate, volume) - Retail:
C_VoiceChat.SpeakText(voiceID, text, rate, volume, false)(different param order)
Setup Constants
- Classic:
UI_DELAY = 0.01(slower updates for older clients) - Retail:
UI_DELAY = 0(immediate updates)