Getting started
Nyx runs inside the WoW 3.3.5a client (build 12340). A loader injects the engine into the running game; the engine removes the client's Lua protection in memory, then reads the framework and your rotations off disk.
The unlock and the engine itself live only in memory and are gone the moment the process exits. One exception: the menu's icons and fonts are written to Interface\Nyx\ inside the game folder, because 3.3.5a can only load textures from there. Nyx.Loader.exe --remove-assets deletes that folder.
It is not tied to any particular server. The patches, offsets and object-manager layout are properties of the 3.3.5a client, so Nyx works against any realm running that build.
What you get that the client does not give you
The 3.3.5a Lua API is missing several things a rotation genuinely needs. The engine supplies them by reading the client's own memory:
| Missing from 3.3.5a | Supplied here |
|---|---|
World coordinates (UnitPosition does not exist) | Nyx.Objects.Player() and every unit table |
| Units you have not targeted | Nyx.Objects.Nearby() |
| Line of sight | Nyx.Objects.LineOfSight() |
| Creature entry IDs | entry on every unit table |
| Hitbox sizes, so melee range is exact | combatReach, Nyx.Objects.InMeleeRange() |
| Drawing in the world | Nyx.Draw |
Everything else — auras, cooldowns, casting — goes through the client's own API, wrapped so the awkward parts are handled. See things that bite for where those wrappers differ from what you might expect.
Naming
The framework lives in one global, Nyx. A short alias _N is defined too, and script authors who want a single letter should take a file-local one:
lua
local N = Nyx -- file-local, collides with nothing
N.Objects.Nearby(8)
Nyx.Objects.Nearby(8) -- canonical, what this reference uses
_N.Objects.Nearby(8) -- built-in aliasA bare global N is deliberately not defined: WoW's globals are one shared table across every addon, and a single capital letter is exactly the sort of name something else grabs for a locale or utility table.
Engine natives sit under Nyx.Engine. You rarely need them directly -- the Nyx.* layer wraps them -- but they are documented, and a few (Nyx.Engine.w2s, Nyx.Engine.los, Nyx.Engine.dump) are useful on their own.
Where your code goes
rotation-bot/External/
├── init.lua the framework's single entry point
├── require.lua the scoped Lua module loader
├── Nyx/ state, safety, priority engine, drawing, and UI
└── Plugins/ the one root for every plugin
└── MyPlugin/
├── manifest.lua plugin metadata
└── init.lua plugin entry pointPut each plugin in its own folder with manifest.lua and init.lua. Its manifest must declare api = 2; its init chunk receives a scoped context as its vararg. Plugin folder order is undefined, so a plugin must not depend on another plugin loading first. /nyx reload re-reads the framework and plugins without restarting the client. See writing a plugin.
If the engine lives somewhere other than the repository, point ZROTATIONS_ROTATION_ROOT at the directory containing Nyx/ and Plugins/.
First run
/nyx status what class and spec it detected, and why it is idle
/nyx list rotations it found
/nyx toggle it onThe status frame's bottom line always says what the engine just did, or why it did nothing — no target, pacing, nothing ready, cast Mutilate. That line is the first place to look when a rotation is not doing what you expect.
Safety
The engine refuses to act while any of these hold, and /nyx status names the one that is blocking:
- a loading screen, or not in the world
- dead or a ghost
- mounted, on a taxi, or in a vehicle
- panicked — the panic key, or repeated script errors
- no attackable target (
Nyx.RequireTarget, on by default) - out of combat, if
Nyx.RequireCombatis on (off by default)
CTRL-SHIFT-X stops it immediately and latches; press again to resume.
Next: writing a plugin.