Appearance
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.
Nothing is written to the client's files, and nothing survives the process exiting.
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/
├── Nyx/ the framework: state, safety, priority engine, drawing
├── Rotations/ your rotations - every .lua here is loaded
└── Nyx.lua the tick and the /nyx commandDrop a .lua file in Rotations/. It is loaded automatically at startup, and /nyx reload re-reads everything without restarting the client.
If the engine lives somewhere other than the repository, point ZROTATIONS_ROTATION_ROOT at the directory containing Nyx/ and Rotations/.
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 rotation.