AI 开发规范(英文)
Document version: 2026-09-24.1. The base format and examples require client 20260919.225455 or later. The plaintext module format version is 1. Canonical full document: https://wa1.io/llm.txt . This specification covers the currently public module capabilities; it is not an index of all WOW APIs. Game API availability depends on the retail/classic version and protected state. Check availability at runtime.
All explanatory prose is maintained in English. Code samples and generated data preserve their actual identifiers, localized spell names, library references, comments, and user-facing strings. Some literals are Chinese: do not translate persisted identifiers or references when using or editing the examples.
1. Agent workflow
Section titled “1. Agent workflow”- Establish the user’s class, game version, desired behavior, and trigger. When editing an existing module, read the entire
.wa1first and preserve unrelated macros, properties, logic IDs, library entries, and hotkeys. - For a new module, start from the complete blank template included below. Produce UTF-8, strict JSON with the
.wa1extension. Code is a plaintext JSON string with newlines escaped as\n. Do not generate internal base64,WA1:, orWA1E1:envelopes. - Put game API queries in property code; one-time setup, event registration, and dynamic macro definitions in
initCode; property-based decisions and key dispatch inluaScripts[].code; overlay drawing inhud. These two Lua environments do not share variables. - Prefer
Macro(slotOrName)for invocation. Define dynamic macros in the game withSuperDPS.SetMacro. Use static macros when their bodies need no dynamic construction. Macro names identify references; hotkeys trigger the actual action. - Keep property names, macro names, and active logic IDs unique. Check every
Prop,Macro, andlibRefreference. Use valid, unique macro hotkeys from the template. A logic start key is a separate client setting, not a macro hotkey. - Validate the schema, array indices, references, and Lua syntax. With repository access, run actual import/round-trip and generator tests. Without a game environment, deliver the file and installation steps, state that game behavior is unverified, and do not claim successful recognition or casting.
- Import the module, bind the required logic start keys, save, and wait for addon generation. Run
/reloadout of combat. For an existing official assisted module containing custom macros, replace only its initialization code and preserve its macro table and logic. Runtime testing must inspect client frame status and actual game behavior.
Suggested task prompt for an agent:
Read https://wa1.io/llm.txt and its linked templates. Implement [specific behavior] for [game version/class] and produce a complete, importable .wa1 file. Keep game-side code separate from desktop logic. Preserve unrelated content and script IDs in any module I provide. Use public APIs, validate the format, indices, references, hotkeys, and Lua syntax, and explain import and /reload steps and which behaviors have not been tested in the game.
2. Architecture and execution boundaries
Section titled “2. Architecture and execution boundaries”Game APIs / native UI display -> Addon properties and dynamic macro readiness -> In-game strip (dedicated numeric glyphs, not general text OCR) -> Rust screen capture, decoding, and integrity checks -> One immutable property frame -> User-triggered desktop Lua logic -> Host hotkey dispatch -> Game secure button executing the macro bodyThe client manages accounts, modules, bindings, capture, and key dispatch. The addon reads game state, renders the strip, and creates/updates secure macro buttons. Dynamic macros are not entries in the game’s account macro panel created with CreateMacro; skills do not need to be manually placed on an action bar. A module cannot call game APIs directly from the desktop.
The timing limits serve different purposes: addon property updates are throttled to 20 ms; the 150 ms frame freshness limit rejects stale actions; dynamic macro replacement first advertises that the macro is unavailable, then waits at least 250 ms and until out of combat before writing the secure button. Do not simulate synchronization with Sleep(250) or change the strip or timing to bypass these checks.
Ordinary values, protected values, and native auras use different transport paths. Rust accepts only complete, validated frames with matching module version, engine generation, and freshness. Never combine data from different screenshots. When the screen is too narrow for one row, the strip wraps by field onto up to 8 rows (clients after 20260919); the client reads every row before validating, and a missing row rejects the frame. Dynamic macro registry snapshots are transmitted in chunks of at most 6 bytes and published only after complete validation. Macro/Cast do not invoke macros during synchronization. Longer names and more records increase synchronization time. A clipped, obscured, or undecodable strip must not cause dispatch using old values. Frame age comes from the capture source; decoding or rereading cached pixels must not renew it.
Macro returning true means only that a hotkey was submitted. It does not prove that the game accepted it, a skill was cast, or an attack hit. A missing property is different from numeric zero. An undefined Prop raises an error; game property execution errors are reported and treated as zero for the current session. Invalid capture data causes action checks to reject execution, rather than treating failure as an actionable zero.
Capture diagnostics
Section titled “Capture diagnostics”For capture failures, system settings can enable automatic diagnostics: failure state and available game pixels are latched promptly, then written asynchronously at most once per second, retaining the latest 10 records. Full queues skip new samples, and missing game frames are reported rather than replaced with a screenshot of WA1. Use the complete diagnostic folder and source-frame age when interpreting evidence.
3. The .wa1 file contract
Section titled “3. The .wa1 file contract”Recommended output is a complete snapshot: 150 macros, 90 props (45 in clients before 20260919; the importer accepts either), 50 luaScripts, and an explicit propLibrary. Keep empty rows even when only a few are used. Each array uses unique, ascending, one-based index values. Do not confuse the 150 macro slots with the logic slot count. The compatibility importer accepts partial fields, comments, and trailing commas, but agents should always generate strict JSON. The recommended schema is stricter than compatibility import.
| Top-level field | Type / rule | Meaning |
|---|---|---|
| format | "wa1-module" |
Plaintext module identifier |
| formatVersion | 1 |
Agents must not invent a higher version |
| name | string | Module display name |
| author | string/null | Author description, not authenticated identity |
| class | string | All, Warrior, Hunter, Rogue, Shaman, Warlock, Priest, Mage, Druid, Paladin, Monk, DemonHunter, DeathKnight, Evoker |
| globalName | string | Prefer SuperDPS; must be a valid Lua identifier. A custom value aliases the addon shared table; it is not the addon directory name |
| spellQueueWindow | positive integer | Spell queue window in milliseconds; template default 250. Not APM or the logic loop interval |
| initCode | string/null | Game Lua 5.1 initialization code, executed once when the addon loads |
| hud | string/null | Desktop Lua HUD script for the whole module (see §4 HUD overlay): runs every 50 ms while the game is connected and only draws; omit or leave empty when the module has no HUD |
| macros | array | Slots 1–105 for ordinary/dynamic macros; 106–150 reserved for target selection |
| props | array | Up to 90 property slots (45 before client 20260919) |
| luaScripts | array | Up to 50 desktop logic slots. The client runs user-bound logic, not every row in array order |
| propLibrary | array | This module’s property library, replaced as a whole |
Cloud module IDs, versions, trigger keys, APM, window mode, account credentials, and addon installation paths are outside this export contract. Do not add unsupported top-level fields to configure them. The client assigns module identity after import; the user configures triggers in the client.
Macro rows
Section titled “Macro rows”{ "index": 1, "hotkey": "ALT-SHIFT-NUMPAD1", "name": "开打", "macro": "/startattack" }
- A static macro requires both a nonempty name and body to generate an action. The assisted example treats a slot as occupied when either
nameormacrois nonempty. - Clear a macro with
name: "", macro: "", keeping a valid hotkey for dynamic use.hotkey: ""explicitly means unbound, not the default binding. - Preserve hotkeys when changing bodies. Avoid duplicate key combinations across all rows, including target slots 106–150. Dynamic registration rejects invalid or conflicting keys.
- Slots 106–150 default to
SelectTarget1–SelectTarget45: player, party1–4, raid1–40. Preserve their names, bodies, and hotkeys when usingSelect. Otherwise they may be explicitly cleared, but retain the rows. - Macro bodies contain game slash commands, not Lua code. Literal
\\nhas historical compatibility handling; new files should consistently use JSON\nescapes for actual line breaks.
Property rows
Section titled “Property rows”{ "index": 1, "name": "Health", "mode": "custom", "params": "player", "libRef": "生命值", "code": "return UnitHealth(arg1)" }
| Field | Rule |
|---|---|
| index | 1–90, the physical file slot. Enabled properties are compacted during generation; logic always reads by name |
| name | Stable, unique reference name. A display language change must not silently rename references |
| mode | custom enables code; disabled retains configuration without enabling it; off is an empty placeholder. Do not generate legacy PropXXXX types for new modules |
| params | At most 3 comma-separated parts. An empty part becomes nil, a parseable finite number becomes number, otherwise string. There is no CSV quote escaping; do not add quotes around string parameters |
| libRef | Library entry name; empty string means independent code. Include both the code snapshot and the matching library entry when referencing a library |
| code | Game Lua function body. May return numbers, booleans, or supported transport values; ordinary tables and arbitrary text cannot be read through Prop |
arg1, arg2, and arg3 are the row’s parameters. Booleans arrive on the desktop as 1/0; numeric properties default to two decimal places. Current clients also accept optional precision: 0..6 (or null) on each props row in .wa1 documents and preserve it through cloud saves and desktop editing. The generated addon applies it before initialization code. Older clients may ignore this additive field; use the initialization function below when targeting earlier September 23 builds. In builds from 2026-09-23 onward, readable (non-secret) numeric properties can use initialization code that calls SuperDPS.SetPropertyPrecision("Facing", 6) to select 0–6 decimals by exact property name; nil restores the default. Explicit precision has a maximum of 16 displayed characters including sign/decimal point; larger values are invalid, not truncated. Secret values retain the existing two-decimal protected rendering path. This is decimal formatting, not lossless float64 transport. Zero is truthy in desktop Lua, so use Prop("InCombat") > 0, not if Prop("InCombat") then.
Logic rows
Section titled “Logic rows”{ "index": 1, "id": 10001, "name": "main", "code": "if Prop(\"Ready\") > 0 then Macro(1) end" }
id is a JSON integer stored as Rust i64; bindings locate logic through it. In new files, give named logic rows unique positive integers such as 10001 and 10002; empty rows may use 0. Preserve the original numeric IDs when editing. Existing IDs often exceed JavaScript’s 2^53-1: do not overwrite a file through ordinary JSON.parse followed by JSON.stringify. Use a parser with large integer support, or Node 24’s JSON.parse reviver context.source with JSON.rawJSON to preserve integer literals. Do not convert IDs to strings; the client rejects string IDs.
code is plaintext desktop Lua, not base64. Do not change existing logic binding IDs to tidy the row order.
Property library
Section titled “Property library”{ "name": "生命值", "params": "player", "code": "return UnitHealth(arg1)", "icon": "" }
The library reuses code. On save, a matching libRef refreshes the row’s code snapshot, while params remain row-specific. Removing a library entry preserves existing snapshots. A missing/null icon uses the default; an empty string hides it. Custom icon values must follow client-supported formats; icons are not game logic. Built-in names are stable references: do not translate persisted values. The complete library and native aura templates extracted from the current Rust implementation are appended below.
Omitted fields, null, and clearing
Section titled “Omitted fields, null, and clearing”Import starts with a default template, then applies field overrides. For most Option fields, omission and null both mean no override, not deletion; an empty string is an explicit override. macros, props, and luaScripts overlay rows by index: [] does not clear template rows. To clear them, supply the relevant rows with empty strings and off mode. propLibrary is replaced as a whole, so [] explicitly clears it. A shortened example with omitted fields is not a lossless patch for an existing user file.
4. Public desktop logic APIs (Lua 5.4)
Section titled “4. Public desktop logic APIs (Lua 5.4)”These functions are available in luaScripts[].code. The game environment has no equivalent global Macro or Prop functions.
| API | Return / behavior | Usage |
|---|---|---|
Prop(name) |
number; error if undefined | Reads the same frame for this action; names are case-sensitive |
Macro(slotOrName) |
boolean, whether submitted | Dynamic slots 1–105; static slots 1–150. Returns false for unready macros, invalid/stale frames, or missing macros; invalid argument types raise errors |
Cast(name) |
nil | Legacy compatibility. Prefer Macro in new code. The first matching static name wins in legacy lookup; avoid depending on ambiguous names |
Select(index) |
nil | 1=player, 2–5=party1–4, 6–45=raid1–40. Invokes a SelectTargetN static macro; success in selecting a target is not guaranteed |
CoolDown(name, ms) |
boolean | First call returns true and records time; returns true again at least ms after the previous true. Script throttling, not a skill cooldown query; the interval is consumed even if the subsequent Macro fails |
SetTimeOut(name, ms) |
nil | Sets/overwrites a monotonic-clock deadline |
GetTimeOut(name) |
boolean | True if never set; otherwise true only when the current time strictly exceeds the deadline |
Sleep(ms) |
nil | Blocks the execution thread. Avoid long sleeps in frequent logic; it cannot wait for a new property frame |
PressKey(vk, holdMs?) |
nil | Windows virtual key code; default hold 200 ms, dispatched by the host. Does not resolve the macro registry or provide macro synchronization. Use Macro for game macros |
Repeated Prop calls in one script always read the same frame; Sleep does not obtain a new screenshot. Game functions such as C_Spell, UnitHealth, and C_Timer do not exist on the desktop. Game-side SuperDPS.Prop is not desktop Prop. Do not rely on undocumented IO, networking, or system libraries.
Prefer starting a throttle only after successful submission (milliseconds):
if Prop("Ready") > 0 and GetTimeOut("main") then if Macro("开打") then SetTimeOut("main", 300) endendSwitching modules or rebuilding the engine resets logic globals and timer dictionaries. Logic scripts in the same module engine share timer keys, so prefix keys by purpose.
HUD overlay (desktop Lua, Hud.*)
Section titled “HUD overlay (desktop Lua, Hud.*)”The module field hud holds the HUD script (module editor → “HUD overlay”). It belongs to the whole module, not to one logic row: the client runs it once per fresh property frame (at most every 50 ms) while the game is connected regardless of trigger keys, every logic script shares the nodes it declares and may update them with Hud.*, and it may only draw. Macro, Cast, Select, Sleep, and PressKey raise errors inside it. The overlay is a click-through window over the game client area, shown only while the game is in the foreground (a debug setting keeps it visible). Coordinates are virtual units: the client area is always 1080 units tall and the width scales; anchor picks one of nine points on the parent (default the whole client area) and x/y offset from it. Requires client 20260918.232050 or later (the build that ships the HUD overlay); older clients ignore the field. Texture / Ring / Sprite nodes, the keys texture rotation mirror desaturate thick from to ccw inverse rows cols frames fps mode shadow spark glow sound exitsound, the spin loop and Hud.Sound / Hud.StopSound need client 20260919.142230 or later (older clients raise “unsupported property” for those keys). Legacy: a logic row named HUD is still accepted and is migrated into hud when the module is next edited; do not generate it in new files.
| API | Behavior |
|---|---|
Hud.Init(fn) |
Runs fn once per engine generation (rearmed by Hud.Clear()); put node declarations here. The engine is rebuilt only when the module content changes (saving an edited module) and the new engine inherits which nodes were visible, so re-declaring the same nodes replays no enter transition or sound |
Hud.Frame(id, spec) / Hud.Text / Hud.Bar / Hud.Icon / Hud.Texture / Hud.Ring / Hud.Sprite |
Create-or-update: the same id only updates the given keys; returns id. Texture draws a built-in texture (masks are tinted by color, color images are drawn as-is), Ring is a vector ring / pie progress, Sprite plays a sprite-sheet stop-motion animation |
Hud.Set(id, key, value) / Hud.Set(id, {k = v}) |
Updates properties; unknown node raises an error. On a node with smooth = ms, numeric and color changes glide to the new value with a critically damped spring (settles in about ms, velocity stays continuous even when the script retargets every tick) |
Hud.Animate(id, {k = v}, ms?, ease?) |
Tweens x y w h alpha value size rotation color bg from their current displayed values to the targets (default 300 ms, outCubic); Hud.Set on the same key cancels the tween |
Hud.Sound(name) / Hud.Sound({ name = "AirHorn", volume = 0.5, loop = true, every = 2000 }) → handle |
Plays a built-in sound (the only side effect allowed in the HUD script; logic scripts may call it too). loop repeats seamlessly until stopped, every replays every N ms |
Hud.StopSound(handle_or_name?, fade_ms?) |
Stops one sound by handle, every sound with that node id / sound name, or (no argument) everything; fade_ms fades out |
Hud.Countdown(id, remaining_s, { voice = "Jim", from = 5, volume = 1 }?) → spoken number or nil |
Countdown voice (needs client 20260919.151727 or later): call it every tick with the seconds remaining; each time ceil(remaining) changes to a new integer within 1..from it plays the built-in sound <voice>_<n> once (voices Amy, David, Jim; from is clamped to 1..10). A reset to a larger value is remembered without speaking; nil / false / ≤ 0 ends the countdown and forgets the id. Hud.StopSound(id) stops the voice |
Hud.Show(id, bool) / Hud.Hide(id) / Hud.Remove(id) / Hud.Clear() |
Visibility, removal (with descendants), full reset. Transitions and sounds are settled once at the end of each script run from the net change: showing plays enter and sound, hiding plays exit and exitsound; a node created and hidden in the same run never appears or plays, hide-then-show within one run is a no-op, remove-then-recreate keeps it as is |
Hud.Flash(id, color?, ms?) |
One-shot highlight, default white 400 ms |
Hud.Loop(id, spec?) |
Sets or clears the node’s continuous animation (same as Hud.Set(id, "loop", spec); no spec = "breathe", false / "none" clears) |
Hud.Pulse(id, on, {period = 800, min = 0.35}?) / Hud.Blink(id, on, period?) |
Legacy toggles for breathing / blinking; prefer the declarative loop key |
Hud.Screen() → w, h / Hud.Visible() |
Client area size in virtual units / whether the overlay is currently shown |
Runtime notes (client 20260919.174712 or later): saving the module rebuilds the engine only when its content changed, keeps the current property values (they are game data, not module content) and hands the visible-node set and countdown state to the new engine, so a save never flashes or replays sounds; while a game window exists but no property frame has arrived yet the HUD script does not run (zeros are not data), and without a game (debug display) it runs on zeros with node sounds muted so layouts can be arranged offline.
Spec keys: anchor (TOPLEFT TOP TOPRIGHT LEFT CENTER RIGHT BOTTOMLEFT BOTTOM BOTTOMRIGHT), x, y, w, h (omitted = zero-size point; text then extends from the anchor), parent (node id, depth ≤ 4), z, hidden, alpha, color (text / icon / bar fill), bg, border, borderw, radius, text, size (font size, default 24), bold, align (left center right), value (0–1), dir (right left up down), icon (built-in icon name such as zap, heart, shield, flame), texture (built-in texture name from the list below: the image of a Texture, the fill texture of a Bar, the sheet of a Sprite), rotation (degrees clockwise; Texture / Icon / Sprite, tweenable), mirror, desaturate, shadow (text shadow color for Text / Bar labels), spark (bright line at a bar’s fill edge), glow (pixel-glow color: bright dashes running around the node’s border), thick / from / to / ccw / inverse (Ring: ring thickness in units, 0 = pie; start / end angle in degrees, 0 = 12 o’clock, clockwise; fill counter-clockwise from the end; draw the unfilled part), rows / cols / frames / fps / mode (Sprite: sheet grid, default 8×8; frame count, 0 = rows × cols; frame rate, default 15; loop / bounce / once / progress — progress picks the frame from value; inverse reverses), sound / exitsound (sound played when the node becomes visible / hidden: a name, or { name = "Boss", volume = 0.6, loop = false, every = 0 }; hiding also stops the node’s looping sound), smooth (milliseconds; later Hud.Set changes to numbers and colors glide with a critically damped spring instead of jumping — give bars smooth = 150), enter / exit (transition played when the node appears / hides), loop (continuous animation while visible). Colors are #RGB, #RRGGBB, #RRGGBBAA, or white black red green blue yellow orange gray. Limits: 200 nodes, 64-character ids, 256-character text, finite numbers only. Three consecutive script errors disable the HUD script until the module is saved or reloaded. string.format("%d") needs an integer in Lua 5.4: wrap fractions in math.floor.
Transitions: enter / exit take a preset name — fade, slideLeft, slideRight, slideUp, slideDown (offset 60 units toward that side while hidden), zoom (scales from 0.6 around the node’s anchor), pop (zoom with an outBack overshoot), none — or a table { kind = "slide", dir = "left", dist = 80, ms = 250, ease = "outCubic" } (zoom accepts from). Defaults: 250 ms in / 180 ms out, outCubic in (outBack for pop) / inCubic out. Slide, zoom and pop also fade; zoom scales the node’s children with it. Continuous animation: loop takes breathe (opacity 1 → 0.35 → 1, 1200 ms), blink (on/off, 600 ms, hides the subtree while off), bounce (up 10 units and back, 700 ms), float (slow 6-unit drift, 2400 ms), shake (±6 units sideways, 400 ms), beat (scales to 1.12× around the anchor and back, 900 ms, children included), spin (one full clockwise turn every 2000 ms, visible on textures / icons / sprites), none, or a table { kind = "bounce", dir = "up", dist = 12, min = 0.3, to = 1.2, ms = 800, ease = "inOutQuad" } (min for breathe, to for beat, dir / dist for bounce / shake). It runs only while the node is visible and stops when hidden; it stacks on top of enter / exit. Easing names: linear inQuad outQuad inOutQuad inCubic outCubic inOutCubic outBack outElastic outBounce. All animation is evaluated per frame by the renderer from timestamps, so script cadence never limits smoothness. Declare nodes with literal values inside Hud.Init — the client’s HUD editor has a visual tab (a simulated canvas plus a property panel) that drags, resizes and edits those literals (including enter / exit / loop) in place; expressions such as y = 100 + base stay code-only.
Textures and sounds (ported from the WeakAuras and BigWigs addons, bundled in the client; only these names work — no local files): mask textures are white shapes tinted by color and may be rotated / mirrored / clipped by a bar; color images (Aura17 Aura21 Aura23 Aura51 Aura71 Aura76 Aura77 Aura78 Aura96 Aura97 Aura98 Aura99 Aura100 Aura114 Aura115 Aura116 Aura118 Aura130 Aura131 Aura138 Aura141 rainbowbar stripe-rainbow-bar cancel-icon cancel-mark ok-icon emoji) are drawn as-is and only support desaturate; stopmotion is the one sprite sheet (8×8, 64 frames). Ring is vector-drawn (no texture). Texture names by category:
- Shapes (37):
Triangle45,arrows_target,blip,beautycase,Circle_White,Circle_AlphaGradient_In,Circle_AlphaGradient_Out,circle_border5,ring_glow3,Circle_White_Border,Square_FullWhite,Ring_10px,Ring_20px,Ring_30px,Ring_40px,square_mini,Circle_Smooth,Circle_Smooth2,Circle_Smooth_Border,Square_Smooth,Square_Smooth_Border,Square_Smooth_Border2,Circle_Squirrel,Circle_Squirrel_Border,Square_Squirrel,Square_Squirrel_Border,Square_White,Square_AlphaGradient,square_border_10px,square_border_1px,square_border_5px,Square_White_Border,target_indicator,target_indicator_glow,Trapezoid,triangle,triangle-border - Bars (11):
BantoBar,Charcoal,Statusbar_Clean,Glaze,Otravi,Smooth,Smoothv2,Smoother,Statusbar_Stripes,Statusbar_Stripes_Thick,Statusbar_Stripes_Thin(Statusbar_*from WeakAuras, the rest from BigWigs: grey gradients folded into alpha, so they look best over a darkbg) - Beams (4):
rainbowbar,stripe-rainbow-bar,StripedTexture,stripe-bar - Icons (7):
cancel-icon,cancel-mark,emoji,exclamation-mark,eyes,ok-icon,targeting-mark - Sheets (1):
stopmotion - PowerAuras Heads-Up (15):
Aura17,Aura18,Aura33,Aura6,Aura28,Aura4,Aura11,Aura3,Aura5,Aura23,Aura1,Aura2,Aura24,Aura16,Aura7 - PowerAuras Icons (69):
Aura131,Aura27,Aura101,Aura141,Aura76,Aura30,Aura132,Aura78,Aura72,Aura34,Aura45,Aura88,Aura25,Aura19,Aura49,Aura26,Aura95,Aura53,Aura87,Aura116,Aura13,Aura119,Aura71,Aura79,Aura143,Aura22,Aura77,Aura114,Aura32,Aura14,Aura110,Aura51,Aura100,Aura96,Aura97,Aura98,Aura99,Aura113,Aura112,Aura70,Aura54,Aura50,Aura142,Aura84,Aura140,Aura29,Aura120,Aura117,Aura69,Aura115,Aura73,Aura8,Aura21,Aura130,Aura35,Aura10,Aura12,Aura74,Aura75,Aura138,Aura9,Aura52,Aura103,Aura139,Aura48,Aura68,Aura118,Aura102,Aura15 - PowerAuras Separated (47):
Aura126,Aura127,Aura128,Aura129,Aura89,Aura90,Aura91,Aura92,Aura93,Aura94,Aura46,Aura47,Aura60,Aura59,Aura61,Aura62,Aura109,Aura108,Aura104,Aura105,Aura107,Aura106,Aura55,Aura56,Aura57,Aura58,Aura133,Aura134,Aura135,Aura136,Aura137,Aura80,Aura82,Aura81,Aura83,Aura66,Aura64,Aura63,Aura65,Aura67,Aura144,Aura145,Aura123,Aura122,Aura124,Aura125,Aura121 - PowerAuras Words (10):
Aura44,Aura43,Aura41,Aura42,interrupt,Aura20,Aura40,Aura39,Aura37,Aura38
Sound names (sound / exitsound / Hud.Sound): AcousticGuitar, aggro, AirHorn, Applause, Arrow_Swoosh, bam, BananaPeelSlip, BatmanPunch, bigkiss, Alarm, Alert, Info, Long, Victory, VictoryClassic, VictoryLong, BikeHorn, BITE, Blast, Bleat, BoxingArenaSound, Brass, burp4, CartoonVoiceBaritone, CartoonWalking, cat2, CatMeow2, chant2, chant4, ChickenAlarm, chimes, cookie, CowMooing, DoubleWhoosh, Drums, ESPARK1, ErrorBeep, Fireball, Gasp, Glass, GoatBleating, shot, heartbeat, HeartbeatSingle, hic3, huh_1, hurricane, hyena, kaching, KittenMeow, moan, OhNo, panther1, phone, bear_polar, PUNCH, rainroof, RingingPhone, RoaringLion, RobotBlip, rocket, RoosterChickenCalls, SharpPunch, SheepBleat, shipswhistle, Shotgun, snakeatt, sneeze, sonar, spell_on_you, spell_under_you, splash, Squeakypig, SqueakyToyShort, SquishFart, swordecho, SynthChord, TadaFanfare, TempleBellHuge, throwknife, thunder, Torch, Adds, Boss, Circle, Cross, Diamond, DontRelease, Empowered, Focus, Idiot, Left, Moon, Next, Portal, Protected, Release, Right, RunAway, Skull, Spread, Square, Stack, Star, Switch, Taunt, Triangle, WarningSiren, WaterDrop, wlaugh, wickedmalelaugh1, wilhelm, wolf5, Xylophone, yeehaw. Countdown voices (from BigWigs, for Hud.Countdown or as plain sounds): Amy_1…Amy_10, David_1…David_10, Jim_1…Jim_10 (one spoken number each); Amy_Countdown1…Amy_Countdown30 are complete N-second countdown tracks (start one with Hud.Sound when a timer begins; it counts down by itself). BigWigs alerts: Alarm, Alert, Info, Long, Victory, VictoryLong, VictoryClassic, spell_on_you, spell_under_you. Sounds are muted while the client’s visual HUD editor is open and by the user’s “HUD sounds” setting; a module should therefore never depend on a sound being heard.
-- 模块 HUD 脚本:不绑键,每 50 毫秒运行一次;只负责显示,不能发键或 Sleep。逻辑脚本可用 Hud.* 更新这里声明的节点Hud.Init(function() Hud.Bar("hp", { anchor = "TOP", y = 140, w = 360, h = 22, color = "#2ecc71", bg = "#00000099", radius = 6, smooth = 150 }) Hud.Text("hpText", { parent = "hp", anchor = "CENTER", size = 16, color = "#ffffff", bold = true }) Hud.Text("combat", { anchor = "TOP", y = 100, size = 28, color = "#ff4d4d", bold = true, text = "战斗中", hidden = true, enter = "pop", exit = "fade", loop = "breathe" }) Hud.Icon("power", { anchor = "TOPRIGHT", x = -40, y = 140, w = 28, h = 28, icon = "zap", color = "#3fa9f5" })end)local hp = Prop("生命百分比") -- 0~1Hud.Set("hp", "value", hp)Hud.Set("hpText", "text", string.format("%d%%", math.floor(hp * 100)))Hud.Set("hp", "color", hp < 0.3 and "#e74c3c" or "#2ecc71")if hp < 0.3 and CoolDown("hud.lowhp", 1000) then Hud.Flash("hp", "#ffffff", 400) endlocal fighting = Prop("战斗中") > 0Hud.Show("combat", fighting)5. Public game-side interfaces (Lua 5.1)
Section titled “5. Public game-side interfaces (Lua 5.1)”initCode and props[].code execute inside the addon; the public namespace is SuperDPS. They may call WOW APIs that exist and are permitted for addons. Lua 5.1 does not support goto, // integer division, bitwise operators, or \u{...} string escapes. Generate Lua 5.1 syntax.
| Interface | Contract |
|---|---|
SuperDPS.SetMacro(slot,name,body) |
See the next section; update during initialization or out-of-combat events |
SuperDPS.DynamicSlots[index] |
Preset snapshot {key,name,occupied}. occupied means a nonempty name or body; dynamic updates do not modify this snapshot. An empty key means invalid/conflicting binding. Read only; do not mutate it to force slot allocation |
SuperDPS.Print(...) |
Prints a game message prefixed with the current addon name; do not call every frame |
SuperDPS.SN(value,tag?,unit?) |
Returns 0 for nil or secret values; returns other values unchanged. Secret diagnostics are deduplicated by call site. Not a number parser; a returned zero does not establish the actual game state |
SuperDPS.RawUnitHealth/RawUnitHealthMax/RawUnitPower/RawUnitPowerMax |
Four preserved original functions. Use for direct transport of protected values; do not perform arbitrary arithmetic on those values |
SuperDPS.Prop |
Module’s game-side shared value table. Initialize keys yourself and return their values from properties to transmit them to the desktop |
SuperDPS.GetUnitAura(unit,aura,filter) |
Lookup by spell ID or name; nil on failure. Legacy multiple-return shape; stacks, duration, expiration, and other values may be sanitized and degraded |
SuperDPS.GetUnitBuff(unit,aura) |
HELPFUL lookup. Actual remaining time/stacks may be unavailable in combat; prefer the native channel for accurate aura fields |
SuperDPS.GetUnitDebuff(unit,aura) |
HARMFUL lookup, with the same constraints |
SuperDPS.HekeliPrimary |
Compatibility field for Hekili recommendations, intentionally spelled Hekeli. Depends on optional Hekili; check existence and value type rather than assuming availability |
SuperDPS.ConfigureAuras(sources) |
Declares native aura sources during initialization; at most 16 distinct source fields |
SuperDPS.Aura(name,field?) |
Defaults to remaining. Returns a transport reference: return it directly; do not perform game Lua arithmetic or comparisons on it |
SuperDPS.BuiltinAura(unit,spell,field,filter?) |
Built-in template reference. The generator recognizes standard templates and registers them automatically. For custom rewrites, use explicit ConfigureAuras/Aura; arbitrary calls are not automatically discovered |
GetSpellInfo/GetSpellCooldown/GetSpellCharges/UnitAura/UnitBuff/UnitDebuff have a legacy multiple-return compatibility layer inside the current addon chunk; this is different from newer C_Spell structured returns. Choose an API explicitly and do not mix positional returns with fields. Internal encoding, layout, markAction, setRow, and MacroMeta are not public module authoring interfaces. IsClassic(), IsMidnight, and CleuAvailable are historical compatibility stubs, not reliable game version detection.
Read-only diagnostic tables: SuperDPS.SecretSeen, SuperDPS.ForbiddenSeen, SuperDPS.ForbiddenDetail, and SuperDPS.AuraDiagnostics. Inspect with game /dump when needed, not by traversing them in property hot paths. Game API secret values cannot be freely compared, used in arithmetic, converted with tostring, or tested for truthiness. Displayability does not imply permission to compute. For decisions that accept a fallback zero, use SN first. To retain an actual displayable numeric value, return it directly through the strip and decide in Rust. Native aura references are a third case: do not reduce them to ordinary numbers with SN.
6. Dynamic macros coexisting with presets
Section titled “6. Dynamic macros coexisting with presets”SetMacro parameters: slot is an integer from 1 to 105; name is 1–96 UTF-8 bytes, with no whitespace-only names, control characters, invalid UTF-8, reserved reload name, or SelectTarget followed by digits. Different slots must not share a name. Body must be nonempty and contain no NUL. The hotkey comes from the existing slot and is not changed by this API.
An initial definition or update returns false,"pending"; identical content that is actually ready returns true,"ready". Invalid parameters raise errors without corrupting the old registry. Updating a slot replaces its name/body and invalidates its old name. Changes exist only for the current game session and are not written back to .wa1; rebuild them on reload. The underlying runtime queues combat-time requests, but modules should defer updates themselves: mark state dirty and process it out of combat.
Minimal initialization when slot 1 has a valid hotkey and overwriting it is intended:
SuperDPS.SetMacro(1, "hello", "/say ready")To preserve presets, use the official assisted example’s allocation policy: scan slots 1–105 once, retain every slot with a nonempty name or body, and append after the last occupied slot. Skip invalid/conflicting bindings. With no presets, start at 1; with a preset at 1, start at 2; with presets at 1 and 5, start at 6 rather than filling 2–4. Recycle only slots owned by the assisted module. If the candidate list exceeds actual available capacity, report an error before rewriting anything; do not overflow or overwrite presets.
The current official assisted example:
- Reads candidates from
C_AssistedCombat.GetRotationSpells, deduplicates usingC_Spell.GetBaseSpell, and resolves localized spell names. - Coalesces login, entering-world, spell-change, player specialization-change, and leaving-combat events into a 100 ms task. During combat it only marks state dirty, then reads the latest list after combat.
- Calls
SetMacroonly for changed macros. Reordering does not write; retained skills keep stable slots. Removed assisted macros are disabled with unique placeholder names and/stopmacro. Records are not physically removed from the synchronization table, whose size remains bounded. - Checks completion only while pending, every 300 ms for at most 20 attempts. Later events may trigger another check. It does not repeatedly rescan candidates.
- Prints an initialization-complete message first and an update-complete message after actual changes. These confirm game macro writes only; client synchronization is still required.
- Adds no extra mounted, chat, death, or distance pause conditions. Returning zero for an unknown recommendation, unavailable API, or invalid data is validity handling.
The official DEMO preserves slot 1, named 开打, with /startattack, and appends assisted macros after it. The official logic still invokes only the recommended skill. This preset demonstrates preservation and is not automatically invoked as an extra action. If the user actually requests it, explicitly call Macro("开打") at the appropriate point after their required conditions. Do not introduce unsolicited target selection or start-attack behavior.
7. Native auras and property library examples
Section titled “7. Native auras and property library examples”Current support is limited to player buffs (HELPFUL) and target hostile debuffs (HARMFUL), not arbitrary unit/filter combinations. There are at most 16 distinct source fields; duplicates are deduplicated, and the 90 property slot limit still applies. An aura may exist with zero stacks; use present for existence.
remaining, duration, and elapsed are seconds. startTime and endTime use the game timeline, not Unix time. remainingPercent and elapsedPercent are native ratios from 0 to 1. applications is the stack count; present is 1/0. dispelType is numeric: 0 none, 1 Magic, 2 Curse, 3 Disease, 4 Poison, 5 Enrage. An absent aura decodes to zero according to slot state; configuration, installation, or recognition errors do not establish actual absence.
Declare sources once in initialization (48265 is an example spell ID; choose one for the intended class):
SuperDPS.ConfigureAuras({ {name="advance", unit="player", filter="HELPFUL", spellId=48265, fields={"remaining", "present"}},})Use two separate property rows:
return SuperDPS.Aura("advance", "remaining")return SuperDPS.Aura("advance", "present")Read Prop("AuraRemaining") and Prop("AuraPresent") in desktop logic. Do not write SuperDPS.Aura(...) > 0 inside game property code. Call ConfigureAuras only once during initialization, not every frame or event. After changing the module, regenerate the addon and /reload out of combat. Standard BuiltinAura templates are included below; row parameters use forms such as player,48265.
8. Performance, errors, and recommended composition
Section titled “8. Performance, errors, and recommended composition”Properties execute frequently, every 20 ms; perform only necessary reads. Create frames, register events/macros, and construct shared tables during initialization. Coalesce bursts of events, bound timer retries, and recheck combat lockdown before writes. Do not continuously poll the entire candidate list or wait for state changes using tight while loops or long Sleep calls in logic.
For a single logic invocation, check conditions in priority order and return after a successful Macro call. This avoids dispatching several mutually exclusive skills from one frame. Query game skill cooldowns through properties; use script CoolDown/GetTimeOut for throttling. Macro bodies should express the intended game conditions without silently adding pause, casting, or target rules the user did not request.
If execution fails, check in order: minimum client version; updated initialization code; enabled properties; name/ID references; slot hotkey conflicts; game messages; out-of-combat reload; full strip visibility; valid client frames and completed synchronization; logic trigger bindings. A false return from Macro is not a signal to rebuild macros indefinitely.
9. Downloads and validation
Section titled “9. Downloads and validation”- https://wa1.io/module.schema.json : Recommended complete output schema; rejects unknown fields. It does not describe every legacy permissive import form.
- https://wa1.io/examples/blank.wa1 : Starting point with all macros/properties/logic explicitly cleared and default hotkeys retained.
- https://wa1.io/examples/static-macro.wa1 : One static macro and one logic script.
- https://wa1.io/examples/dynamic-macro.wa1 : Creation with SetMacro and invocation with Macro.
- https://wa1.io/examples/aura-library.wa1 : Native auras, an ordinary parameterized property, and library references. Observation only; dispatches no keys.
- https://wa1.io/examples/target-selection.wa1 : Preserves default target macros and demonstrates Select/timer calls. Confirm the intended target behavior before use.
- https://wa1.io/examples/hud-basic.wa1 : A module
hudscript drawing a health bar, a combat label, and an icon from two properties. Display only; dispatches no keys. - https://wa1.io/examples/hud-demo.wa1 : HUD showcase and stress test. One
hudscript demonstrates every node kind (Frame with bg / border / radius / z, Text sizes, Bar in four directions, Icon), alllooppresets and the table form, the sevenenter/exitpresets toggling on timers,Hud.Animatecycling through the ten easings,smoothversus no smooth,Hud.Flash/Hud.Pulse/Hud.Blink/ runtimeHud.Loopswitching, and a live-data row from two properties. The bottom panel createsSTRESSbars (default 100, capped so the total stays under the 200-node limit) whose values and colours change every tick with alternating breathe / beat / smooth; edit theSTRESSconstant to size the test. Drives itself withos.clock(), so it runs without a game when the debug display is on. Display only. - https://wa1.io/examples/hud-media.wa1 : Textures and sounds. A spinning aura texture tinted orange, a ring cooldown with a shadowed countdown label, a striped health bar with a spark that glows red when low, a stop-motion sprite shown in combat, a
Hud.Countdownvoice (Jim) reading 5…1 on the ring, and a low-health warning label that playsWarningSirenwhen it appears. Uses only built-in texture / sound names (WeakAuras and BigWigs). Display only. - https://wa1.io/examples/target-range.wa1 : Target range HUD driven by manually configured spells. Exact distance is not obtainable for hostile units under 12.0 secret values (
UnitDistanceSquaredis group-only and nil in instances; item range and interact distance are blocked in combat), so each rung property射程1..4takes two parameters, the spell ID used against hostile targets and the one used against friendly targets (leave either empty to skip that kind), and returnsC_Spell.IsSpellInRangefor the applicable spell untouched (a secret boolean in combat, transported as 1 / 0; 3 = no target, 2 = not checked because unset, unknown or not castable on this target).initCodeonly supplies helpers: it looks up each spell’s min / max range, prints one chat line per spell the first time it is seen, and registers the rungs each tick so射程表/射程下限表(which must precede the rung properties) can pack max / min yards asr1 + r2*100 + r3*10000 + r4*1000000. Secret values cannot be combined or tested in game Lua, so one property per rung is required; thehudscript intersects the rung results into the feasible distance interval (a rung with a minimum range that reports out of range may be too close or too far) and shows a bracket such as8 – 35 码. On-next-swing melee abilities (Raptor Strike, Heroic Strike, Cleave, Maul) always report in range and must not be used. Display only. - https://wa1.io/examples/official-assisted-demo.wa1 : Complete DEMO preserving
开打and automatically appending assisted macros. - https://wa1.io/examples/official-assisted-dynamic.wa1 : Existing compact example URL, with an empty macro table, preserving its original usage.
- https://wa1.io/examples/official-assisted-init.lua : Initialization code for updating an existing module without replacing the rest of it.
These examples demonstrate combinations of implemented capabilities; a single DEMO does not automatically run every action. Users configure desktop start keys and APM; account credentials and market publication are not embedded. When editing legacy modules, preserve original format content, especially IDs greater than 2^53 and legacy mode codes. The strict new-file schema is not a reason to delete historical fields.
Examples are checked against the real importer, cloud round-trip and generator, and every Lua block is syntax-checked with official Lua 5.1 before publication. These checks do not start the game or dispatch real keys, and do not establish casting success rates.
10. Sources and ongoing synchronization
Section titled “10. Sources and ongoing synchronization”Explanatory prose is maintained manually in English; templates and built-in library data come from the client’s actual export. Publication stops whenever the underlying client sources change until this contract is reviewed again. The document version and minimum client version change only when semantics or required capabilities change; ordinary wording changes do not imply new client capabilities. The generator appends the format schema, built-in library and complete templates/examples below; the full document is self-contained for module generation and requires no website login. Source-derived code and data keep their original strings even when they are not English.