v0.11.0-bcc
What's new
Extended Macro UI
v0.11.0 (2026-10-20)
Full Changelog Previous Releases
- Add CurseForge release automation and release skill
Add a tag-triggered GitHub Actions workflow that packages the addon with
the BigWigs packager and uploads it to CurseForge, a luacheck CI workflow,
a .pkgmeta describing the package and dev-only files to exclude, and a
/release skill that bumps the version, lints, commits, tags and pushes.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com - Add LDB launcher and optional minimap button
Embeds LibStub, CallbackHandler-1.0, LibDataBroker-1.1 and LibDBIcon-1.0
under Libs/. A launcher data object (Titan Panel and other broker
displays, plus a LibDBIcon minimap button) toggles the window on
left-click and opens a Saved Messages send menu on right-click. The
minimap button is on by default and can be hidden in the EMU settings.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com - Consolidate duplicated UI and data code into shared helpers
- Docked side panels (icon picker, macro builder, import/export) share a
mixin for IsShown/Close/Toggle and close each other via ns.CloseDockPanels. - Shared list view, empty-state text, inset-height, radio, menu-tooltip,
pipe-escape, A->Z sort helpers and the "?" icon constant in Core.lua. - Messages owns CopyOutputs and a single create path for New, Duplicate
and Import; MessageEditor and Transfer reuse it.
No behavior change intended.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Docked side panels (icon picker, macro builder, import/export) share a
- Show item and spell tooltips beside the Macro Builder list
Hovering a list row shows the game tooltip docked to the right of the
builder: worn/bag slot for items (with enchants and durability), item or
spell id otherwise. Saved messages and ItemRack sets show none.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com - Add Equip Item and ItemRack actions to the Macro Builder
- Equip Item: lists wearable gear from bags and worn slots; emits /equip,
or /equipslot with a slot choice for one-handed weapons, trinkets and
rings (defaulting to the slot the item is already worn in). - ItemRack: Equip Set: grayed out unless ItemRack is loaded; lists sets from
ItemRackUser.Sets (falls back to typing the name) and emits
/itemrack equip <set>. - Use Item: gear that must be worn gets an /equip (or /equipslot with the
same slot choice) line before the /use; worn on-use items are listed too. - Target: add @cursor.
- Hide Target/Modifier rows for actions that don't honor them, without
leaving gaps; update the extend-macro-builder skill doc.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
- Equip Item: lists wearable gear from bags and worn slots; emits /equip,
- Add Import/Export wizard for macros and saved messages
A docked side panel, opened from a new header button, that exports all or
selected General/Character macros and Saved Messages to a shareable string
(!EMU:<v>! + Base64(Deflate(CBOR)) via C_EncodingUtil, with character,
realm, timestamp and addon version metadata) and imports one with per-item
selection, preview, and an overwrite-or-copy conflict policy. Import results
are reported in chat; failures are also raised through geterrorhandler so
BugSack/BugGrabber capture them.
The wizard and the Macro Builder now size their height to their content.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com - Fix Run button hidden behind Blizzard's TimerTracker
The earlier TradeSkillMaster layering fix moved the secure Run button from
DIALOG down to the window's HIGH strata. That placed it beneath Blizzard's
TimerTracker -- a full-screen, always-present DIALOG frame -- so the button was
occluded and appeared to be missing.- Editor: the Run button is set to DIALOG strata (above TimerTracker, so it's
visible) at a low frame level (2), so a focused DIALOG-strata window still
raises above it instead of the button floating on top in the common case. - README: documents the remaining edge case -- the button can still layer above
other DIALOG-strata addon windows (e.g. TradeSkillMaster) -- as a known issue.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Editor: the Run button is set to DIALOG strata (above TimerTracker, so it's
- Add a Saved Message action to the Macro Builder
The Macro Builder's action dropdown gains a "Saved Message" option alongside
Cast Spell and Use Item. It lists the player's saved messages (fuzzy-searchable
via the same search box) and, on Insert, writes an "/emu send <name>" line into
the macro being edited.- Saved messages are picked from the list only (no manual name entry), so the
name box is hidden for this action; the list selection is the source of truth. - Target/Modifier conditionals and the Rank box are hidden for this action,
since /emu send takes only a name. - Compose emits "/emu send <name>"; Describe reads "Sends the saved message ...".
- List rows without an icon (saved messages) now start the name at the left edge.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Saved messages are picked from the list only (no manual name entry), so the
- Allow dragging macros from the list onto action bars
Macro list rows now RegisterForDrag("LeftButton") and PickupMacro(index) on
drag start -- the same mechanism Blizzard's own macro frame uses, so the macro
lands on the cursor and the player drops it on an action bar (the secure action
button handles the placement; nothing is tainted). Left-click still selects;
only a click-drag picks up. Message rows carry no macro index, so dragging them
there is a no-op.
Verified against Blizzard_MacroUI in the classic_era source.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com - Add duplicate button for macros and saved messages
A per-row duplicate control that appears on hover, right-justified, as a small
red square button in the settings-gear style, with a tooltip. Works on General
Macros, Character Macros and Saved Messages.- MainFrame: InitRow builds the hover button (shown via the row's mouseover,
tucking the dirty dot aside so they don't overlap). It's disabled with an
explanatory tooltip when there's no free macro slot or in combat; always
enabled for messages (no slot limit). DuplicateItem routes to macro/message;
duplicating while the editor is dirty goes through the usual Save/Discard/
Cancel prompt (the copy is built from captured name/icon/body, so a reindex
after Save is fine). The new entry is selected, opened in the editor and its
name focused. - Core: ns.NameWithSuffix(name, suffix, maxLen) appends a suffix, trimming the
end of the name so a copy of a max-length (16-char) macro name still fits
instead of overflowing the limit. - Messages: Messages.Duplicate(id) copies content + checked outputs under a
unique " Copy" name (names drive /emu send).
Macros use CreateMacro (created and saved immediately); the glyph is
Character-Plus since the classic assets have no dedicated copy icon.
API verified against the classic_era source. luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- MainFrame: InitRow builds the hover button (shown via the row's mouseover,
- Align the Saved Messages editor fields to a shared width
The message-text box was inset ~6px on each side relative to the name box and
the output checklist, so it looked narrower than the fields around it. Widen it
to the shared area +10 / -10 edges and align the "Send to:" label so the
checklist (anchored to that label) keeps the same edge. The Message Name,
message text and Send to boxes now share one width with aligned left/right edges.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com - Lower the anti-spam minimum interval to 0.5 seconds
- Core: the settings slider now ranges 0.5-60 in 0.5s steps (so whole seconds
stay selectable) with a decimal-aware label ("%g sec", e.g. "0.5 sec"). - Messages: GetInterval clamps to a 0.5s floor (MIN_INTERVAL) instead of 1.
Default remains 15 seconds. luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Core: the settings slider now ranges 0.5-60 in 0.5s steps (so whole seconds
- Skip ineligible message outputs to prevent chat error spam
A saved message's checked outputs are now filtered by whether they can actually
receive a message, so the addon never fires a doomed send that floods the
player's chat with "You aren't in a party" and similar error replies.
Per-output gating in Messages.Send (CanSendFixed), mirroring the eligibility the
default chat editbox uses, plus the raid-warning and officer permission checks:- Party: only when in a group (IsInGroup).
- Raid: only when in a raid (IsInRaid).
- Raid Warning: only in a raid and as leader/assistant.
- Instance (BG): only when in an instance group (IsInGroup INSTANCE).
- Guild: only when in a guild.
- Officer: only when in a guild and C_GuildInfo.IsGuildOfficer().
- Global channel: only when currently joined (unchanged behavior).
- Say/Yell: always attempted.
Ineligible outputs are skipped silently; if nothing is eligible the send is a
no-op and does not start the anti-spam cooldown (that only begins once a message
actually goes out).
APIs verified against the classic_era source. luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Add a global anti-spam interval for message sending
Prevents any saved message the addon can send from going out more often than a
configurable interval, guarding against accidental or intentional spam.- Messages: a single shared Messages.lastSend timestamp (GetTime), so the
throttle is global across every message and every send path -- the "Send Now"
button and /emu send alike. Messages.Send now returns early with a chat notice
("Anti-spam: wait N more second(s)...") when a send comes too soon, and only
starts the cooldown once something actually went out. New helpers
GetInterval() (clamped to a 1s floor) and ThrottleRemaining(). - Core: sendInterval (default 15) added to the SavedVariables defaults, plus a
slider in the EMU settings panel (1-60s, step 1, "N sec"), built with the
modern Settings API (CreateSliderOptions / CreateSlider).
API verified against the classic_era source. luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Messages: a single shared Messages.lastSend timestamp (GetTime), so the
- Refactor: extract shared UI helpers for lists, rows, prompts and inputs
Pull repeated UI boilerplate into documented helpers in Core.lua and use them
across the five UI files. Behavior is unchanged -- anchors, insets, draw layers
and event wiring are preserved exactly.
New Core helpers:- ns.IsBlank(text): nil/empty/whitespace check (replaces a NameIsBlank local
duplicated in both editors). - ns.CreateScrollList(parent, rightInset): the InsetFrame + WowScrollBoxList +
MinimalScrollBar scaffold shared by all four scrolling lists. rightInset
defaults to 24; the icon grid and builder list pass 22 to keep their widths. - ns.AddRowHighlight(button): the gold selected background + white hover
highlight used by the macro/message list and the builder list. - ns.CreatePrompt(parent, title, hint): the centered "No X selected" placeholder
both editor panes show. - ns.CreateMultilineInput(parent, maxLetters): the InputScrollFrame text box with
the char counter hidden and the editbox width kept in sync.
Call sites in MainFrame, IconPicker, MacroBuilder, MessageEditor and Editor drop
their copies of that boilerplate. Also removed two now-unused SCROLLBAR_WIDTH
constants and an unused strtrim cache.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- ns.IsBlank(text): nil/empty/whitespace check (replaces a NameIsBlank local
- Add extend-macro-builder Claude skill
A project skill (.claude/skills/extend-macro-builder/SKILL.md) documenting how
to add features to the Macro Builder: the command data flow (Compose / Describe
/ EffectiveName / UpdatePreview / UpdateVisibility / RefreshList), step-by-step
recipes for adding a Target option, a Modifier option, or a whole new action
type, plus the standing rules (verify APIs against the classic_era source,
luacheck clean on addon files only, no taint, in-game test checklist).
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com - Add Macro Builder side panel for composing /cast and /use commands
A guided panel, opened by a new "Macro Builder" button in the macro editor,
that composes a single /cast or /use command and inserts it as a new line into
the macro being edited. It never writes macros itself -- it only appends to the
editor's draft, so the normal dirty/Save flow applies. Not available for Saved
Messages.- New MacroBuilder.lua: pure data helpers (known-spell and bag-item enumeration,
rank-prefix lookup, command composition and a plain-language description) plus
a docked window modeled on the icon picker. The two side panels share the
dock slot and are mutually exclusive. - One name box (spell or item) is the single source of truth: the searchable
list, typing, and Shift-click all fill it. Shift-click is caught with a
taint-free post-hook on ChatFrameUtil.InsertLink, which both item and spell
links funnel through on this client. - The item list is filtered to usable items (C_Item.GetItemSpell), so reagents
and plain gear are excluded. - Target and Modifier are single-select dropdowns that compose one conditional
clause, e.g. /cast [@mouseover,mod:alt] Fireball. Each option has a tooltip.
Targets: player/target/targettarget/focus/focustarget/mouseover/pet.
Modifiers: any (mod) / alt / ctrl / shift / mouse buttons 1-5. - Optional Rank field (down-ranking) for spells that have ranks; the localized
"(Rank N)" prefix is derived from the spell's own subtext, not hardcoded. - A live preview of the command plus a friendly explanation of what it does.
- Editor: a "Macro Builder" button beside "Change Icon" (row re-anchored to the
pane's left edge so both fit); Editor:InsertBodyLine appends a line and
refuses rather than overflowing the 255-char limit. The builder closes with
the window, on the Saved Messages tab, and when no macro is selected.
All spell/item/chat APIs verified against the classic_era source.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- New MacroBuilder.lua: pure data helpers (known-spell and bag-item enumeration,
- Fix Run button layering and add a settings gear button
- Editor: the secure Run button (parented to UIParent so the window stays
unprotected) no longer sits at DIALOG strata, where it floated above
unrelated frames like TradeSkillMaster. It now syncs to the main window's
own strata and a level just above it in SyncRun (out of combat only), so it
layers with the window and drops behind other frames when the window does. - MainFrame: added a gear button left of "Macro" that opens the addon's
settings page (ns.OpenOptions). It's a standard red panel button matching
the others, with Blizzard's OptionsIcon-Brown gear glyph via inline atlas
markup.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Editor: the secure Run button (parented to UIParent so the window stays
- Add Saved Messages tab for multi-channel broadcasts
A MessageBarker-style feature: a third "Saved Messages" tab for storing
named chat messages that broadcast to several destinations at once. These
live in SavedVariables, entirely outside the macro system, so they never
consume macro slots.- Messages.lua: data layer (storage, A->Z list, send, channel enumeration).
Outputs are say/yell/party/raid/raid warning/instance/guild/officer plus
every currently joined channel. Sends via C_ChatInfo.SendChatMessage from
hardware events only (button click or slash), with channel ids resolved
through GetChannelName. Names are unique (case-insensitive): New
auto-suffixes and Save refuses a duplicate, so slash resolution is
unambiguous. - MessageEditor.lua: right-pane editor with a name box, multi-line content
box (255-char counter), a scrolling output checklist, and Send Now. Shows
the "/emu send <name>" command for pasting into a game macro, and warns
inline on a blank/duplicate name. - MainFrame.lua: generalized the list/selection/editor plumbing to drive
either editor, added the third tab (macro tab labels shortened to fit),
and moved the unsaved-changes notice to a shared window footer so it no
longer overlaps editor fields. - Core.lua: SavedVariables defaults (messages, nextMessageId) and the
"/emu send <name>" slash subcommand. - Editor.lua: common editor interface (GetEditingKey/LoadItem/SetActive),
active-aware Run button, Save returns success. - TOC bumped to 0.8.0; new globals added to .luacheckrc; MessageBarker/
reference addon gitignored.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Messages.lua: data layer (storage, A->Z list, send, channel enumeration).
- Narrow the editor pane to match the native macro editor
- MainFrame: MAIN_WIDTH 600 -> 552, so the editor pane's body box is
~286 wide, matching Blizzard's native macro command box. - Editor: move the body character counter onto its own line under the
"Enter Macro Commands" label, and relocate the "Unsaved changes" label
to its own line above Save/Cancel so the bottom row stays uncramped at
the narrower width. The body box is re-anchored between them.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- MainFrame: MAIN_WIDTH 600 -> 552, so the editor pane's body box is
- Refactor: shared UI helpers and DRY cleanups
Behavior-preserving simplification; no functional changes.- Core: add ns.CreateButton, ns.CreatePortraitWindow, ns.TrimIcon and
ns.MUTED_COLOR / ns.SetMutedText, and use them for the EMU button. - MacroData: extract ForEachMacro and express GetMacros / FindBySnapshot
in terms of it, removing the duplicated base+slot iteration. - Editor: collapse OnNameTyped to its real job (the two-way icon-picker
name sync was dead since the picker's name box was removed); use the
button/icon/color helpers. - MainFrame + IconPicker: build their windows and buttons via the shared
helpers; crop icons with ns.TrimIcon; use CELL_SIZE for the grid
selection overlay.
luacheck: 0 warnings / 0 errors.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Core: add ns.CreateButton, ns.CreatePortraitWindow, ns.TrimIcon and
- Add locked UI-panel layout mode and options panel
The main window now defaults to a managed UI panel (registered in
UIPanelWindows like Blizzard's MacroFrame), so it opens in a fixed
position and pushes alongside other panels such as the character panel
and spellbook. A new option restores the previous free-floating,
drag-anywhere behavior.- Core: ApplyLayoutMode / OpenMain / CloseMain / SetLockToPanel route
open/close through ShowUIPanel+HideUIPanel (locked) or raw Show/Hide
(floating), keep the frame out of UISpecialFrames when panel-managed,
and defer layout changes made in combat to PLAYER_REGEN_ENABLED. - Options panel via the modern Settings API with two checkboxes:
"Lock window as a UI panel" (default on) and "Use as the default
macro window (/macro)" (equivalent to /emu macro). New slash verbs:
/emu lock | unlock | options | help. - MainFrame: RestorePosition is mode-aware; dragging is gated to
floating mode.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- Core: ApplyLayoutMode / OpenMain / CloseMain / SetLockToPanel route
- Initial commit: Extended Macro UI addon
A replacement macro window for WoW Classic: tabbed account/character lists,
fuzzy search with highlighting, a full editor (name/body counters, dirty
tracking, Save/Cancel/New/Delete), a secure Run button, a docked icon picker,
combat-safe handling, and EMU/native window switching.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
This mod has no additional files

