Last Updated: 2026-03-12 Current Phase: Step 6 — Final Documentation + Release Validation Pass Status: Step 6 documentation/release validation complete; release commit/publish flow in progress ⏳
Status: ✅ VALIDATED (2026-03-12)
Implemented in code:
- Added shared spell bucket in performance routing:
SPELL_UPDATE_COOLDOWN+SPELL_UPDATE_CHARGES-> one coalesced dispatch bucket
- Added
BAG_UPDATEdebounce in performance coalescer path - Routed low-risk handlers to CustomTrackers update paths (without broad full-frame refresh)
- Added lightweight debug counters with slash helpers:
/suf coalescer reset/suf coalescer
Validation checklist (single dungeon run):
- Before entering dungeon: run
/suf coalescer reset - Complete one dungeon run with performance integration enabled
- After run: run
/suf coalescer - Confirm spell bucket shows reduced
raw -> dispatched - Confirm bag debounce shows reduced
raw -> dispatched - Confirm CustomTracker bars still update correctly for cooldown/charges/bag-driven changes
Observed result (2026-03-12):
/suf coalescerreported:SPELL_UPDATE_COOLDOWN+SPELL_UPDATE_CHARGES 6002 -> 2700(~55.0% reduction)/suf coalescerreported:BAG_UPDATE 38 -> 21(~44.7% reduction)- CustomTracker bars updated correctly for cooldown, charges, and bag-driven changes during the run.
Next if validation passes:
- Expand coalescer coverage to the next safest non-unit buckets only (incremental rollout).
Status: ✅ VALIDATED (2026-03-12)
Implemented in code:
- Added 7-slot DataText layout (
outerLeft,farLeft,left,center,right,farRight,outerRight) - Added per-slot LDB display mode controls (
AUTO,TEXT,ICON,ICON_TEXT) - Increased default DataText panel height to 40 (double-height baseline)
- Expanded width control max and runtime clamp so panel can fill full screen width
- Moved DataText dropdown controls higher in both OptionsV2 and legacy GUI sections
Step 5c Validation Checklist:
- Switch to
7 Slots (Extended)and verify all seven entries render without overlap - Verify
Outer Left/Outer Rightsource dropdowns enable only in 7-slot layout - Verify DataText width can be adjusted to full screen width and clamps correctly
- Verify default/new profile DataText height starts at 40px
- Verify LDB display mode per-slot (
AUTO/TEXT/ICON/ICON_TEXT) renders as expected - Verify dropdown ordering in GUI matches updated top-priority control flow
Observed result (2026-03-12):
- Full Step 5c validation passed in-game with no reported problems.
Status: ✅ VALIDATED (2026-03-12)
Implemented in code:
- Enhanced LDB text rendering in DataText buttons:
- supports icon + text/value/label fallback composition
- Added robust LDB tooltip fallback path when broker has no
OnTooltipShow:- supports
tooltiptext,value/suffix, multiline rows
- supports
- Added hover compatibility for broker callbacks:
OnEnter/OnLeavesupport- hovered-source tracking for tooltip refresh
- Added click compatibility improvements:
AnyUpclick registration- dispatch
OnClick(frame, button)with fallback toOnMouseUp
- Added live LibDataBroker attribute callback handling:
LibDataBroker_AttributeChangednow triggers datatext refresh- active tooltip refreshes while hovered on relevant key changes
Step 5b Validation Checklist:
- Test with an LDB launcher addon (icon/label only) and verify click opens expected panel
- Test with an LDB data source addon (
textupdates) and verify DataText updates without waiting for ticker cycle - Verify tooltip fallback renders when broker has no
OnTooltipShow - Verify broker-provided tooltip still works when
OnTooltipShowexists - Verify broker
OnEnter/OnLeavepaths do not break tooltip lifecycle - Verify middle/right click dispatch for LDB sources registered for those buttons
Observed result (2026-03-12):
- Full Step 5b validation passed in-game; LDB tooltip and click behavior showed and worked correctly.
Next after Step 5b validation:
- Fold any addon-specific click edge cases into a tiny compatibility shim (only if needed).
Status: ✅ VALIDATED (2026-03-12)
Implemented in code:
- Upgraded builtin
Currenciesdatatext provider with cap-aware formatting and weekly progress tooltip rows. - Added builtin
Reputationdatatext provider with support for:- standard standings,
- friendship standings,
- major faction renown,
- paragon reward-pending state.
- Upgraded reputation databar text/tooltip to use the same normalized watched-faction logic.
- Added event-driven refresh wiring for faction/currency/renown updates:
UPDATE_FACTIONCURRENCY_DISPLAY_UPDATEMAJOR_FACTION_RENOWN_LEVEL_CHANGEDMAJOR_FACTION_UNLOCKED
Step 3 Validation Checklist:
- Select
Currenciesin a DataText slot and verify cap + weekly rows in tooltip - Select
Reputationin a DataText slot and verify normal standing/progress display - Verify friendship faction watched display (rank text + progress handling)
- Verify major faction watched display (renown styling/progress)
- Verify paragon watched display and pending reward indicator (
!+ tooltip line) - Verify reputation databar tooltip matches datatext standing/progress state
- Verify left-click actions (
TokenFramefor currencies,ReputationFramefor reputation) - Verify event-driven updates after rep/currency changes without requiring UI reload
Observed result (2026-03-12):
- Full Step 3 validation passed in-game; the upgraded provider and databar behavior showed and worked correctly.
Status: ✅ VALIDATED (2026-03-12)
Implemented in code:
- Added configurable datatext slot layout (
3classic /5expanded) with profile keydatatext.panel.slotCount. - Expanded slot model to support
farLeftandfarRightalongsideleft/center/right. - Refactored DataText panel runtime layout to dynamically size/position buttons per active slot count.
- Added configuration controls in both OptionsV2 and legacy OptionsWindow for layout + far slot source assignment.
Step 5 Validation Checklist:
- Switch to
5 Slots (Expanded)and verify five datatext fields render with no overlap at default width - Verify
farLeftandfarRightsource dropdowns become enabled only in 5-slot layout - Verify switching back to
3 Slots (Classic)hides far slots and preserves left/center/right content - Verify drag/edit mode still works for the panel in both layouts
- Verify tooltip/click behavior still works for all visible slots (builtin/custom/LDB)
- Verify
SystemandLDB:*slot assignments persist and render correctly after/reloadand fresh login (no reselect required)
Observed result (2026-03-12):
- Full Step 5 validation passed in-game; the panel layout expansion and related databar/datatext behavior showed and worked correctly.
Next after Step 3 + Step 5 validation:
- Step 6: Final documentation + release validation pass
Status: 🟡 IN PROGRESS (2026-03-12)
Completed at kickoff:
- Refresh CHANGELOG.md for
1.33.1with validated DataText and coalescer work - Refresh README.md recent updates, commands, and feature summary for the current validated feature set
Remaining Step 6 checklist:
- Do a final release-metadata consistency pass (
SimpleUnitFrames.toc, changelog version, README release references) - Draft the final release summary / publish notes for the validated DataText and coalescer work
- Decide whether coalescer expansion is release-blocking or deferred to the next work cycle
- Confirm no additional documentation updates are needed before packaging/release prep
Step 6 result (2026-03-12):
SimpleUnitFrames.toc(1.33.1.31226), CHANGELOG.md, and README.md are aligned on1.33.1release metadata.- Final publish notes drafted in
RELEASE_NOTES_v1.33.1.md. - Validated low-risk coalescer work is included in this release scope; broader next-bucket expansion is deferred to follow-up work.
Status: ✅ VALIDATED (2026-03-12)
Objective: Display Shaman totem information (slot 1-4) above player auras via oUF Totems element
-
Totems Widget Constructor (CreateTotems function):
- Creates 4 totem button frames (36px × 36px each, 4px spacing)
- Each button has Icon texture and Cooldown CooldownFrame
- Follows oUF element contract per Libraries/oUF/elements/totems.lua
-
Player Frame Instantiation (Shaman-gated):
- Added CreateTotems call in player Style (line ~8991-9000)
- Guards with UnitClassBase check to ensure Shamans only
-
Dynamic Anchor Chain (ApplySize layout):
- Primary anchor: Above Auras (if visible) — respects multi-row aura layout
- Fallback 1: Above ClassPowerAnchor (if visible) — for when auras disabled
- Fallback 2: Above AdditionalPower (if visible) — secondary fallback
- Fallback 3: Above main frame (if nothing else visible)
- Prevents totem disappearance under any configuration
-
Event Integration (Dirty event routing):
- PLAYER_TOTEM_UPDATE event coalesced with power events
- IsFrameEventRelevant updated to recognize Totems
- UpdateFrameFromDirtyEvents routes updates to Totems element
-
Spec-Change Reliability (OnClassResourceContextChanged):
- Added Totems.ForceUpdate hook alongside ClassPower/AdditionalPower
- Ensures clean state on spec/form transitions
- SimpleUnitFrames.lua (5 locations):
- Line ~7654-7682: CreateTotems function (28 lines)
- Line ~8991-9000: Player Style instantiation (9 lines)
- Line ~7376-7421: ApplySize anchoring logic (46 lines)
- Line ~3282: IsFrameEventRelevant Totems check (1 line modified)
- Line ~3382: UpdateFrameFromDirtyEvents SafeUpdateElement (1 line added)
- Line ~10037-10039: OnClassResourceContextChanged ForceUpdate (3 lines added)
- Cast behavior: Cast a totem and verify it appears above auras with icon/cooldown
- Expiration: Totem expires after duration ends; frame hides cleanly
- Replacement: Replace active totem (e.g., swap fire totem); new one renders correctly
- Multi-row auras: With 12+ auras causing 2-row layout, totems stay above full stack
- Auras disabled: Hide player auras; verify totems anchor to ClassPowerAnchor (or fallback) and remain visible
- Spec switch: Swap specs (e.g., Enhancement ↔ Restoration); totems update cleanly without stale state
- Form changes: Shapeshift forms (e.g., Bear/Cat for Druid mains) don't break totem layout
- Combat context: Cast totems in combat; verify event handling works without combat lockdown issues
Observed result (2026-03-12):
- Shaman Totems integration worked in-game with no reported problems or errors.
- Code Reuse: Follows existing class-resource patterns (CreateClassPower, CreateAuras)
- Maintainability: Zero custom event handling; relies on oUF's built-in PLAYER_TOTEM_UPDATE
- Performance: Minimal overhead; event-driven with dirty coalescing (included in power event batch)
- Compatibility: Works with existing aura/class-power/additional-power layout system
- Totem Size: Currently hard-coded to 36px × 36px (no UI customization yet)
- Totem Dismiss: Right-click functionality not implemented (future enhancement)
- Keybindings: No default keybindings for totem casting (rely on Blizzard defaults)
- Multi-class: Implementation Shaman-specific (other classes don't benefit; patch as needed if added)
- ✅ Code implementation complete
- ✅ In-game testing complete
- ✅ No bug-fix cycle required from current validation
- ✅ WORK_SUMMARY.md updated with final validated status
- ⏳ Consider optional enhancements (configurable size, positioning, right-click dismiss)
Low-effort, high-confidence enhancements. Start here.
Scope update: Task 1.1 removed. Focus is Midnight API 12.0.x only.
Objective: Add 4 missing safe value wrappers (SafeCompare, SafeArithmetic, SafeToNumber, SafeToString)
Status: ✅ COMPLETE (2026-03-03)
What to Do:
- Open SimpleUnitFrames.lua safe value section (lines ~765-835)
- Add functions:
SafeCompare(a, b) -- Compare values without arithmetic SafeArithmetic(val, op, fall) -- Safe arithmetic (+, -, *, /, %) SafeToNumber(val, fall) -- Convert to number with pcall SafeToString(val, fall) -- Convert to string with pcall
- Add to addon helper exports (_core)
- Document pattern (comment block at top)
Files to Modify:
- SimpleUnitFrames.lua (safe helpers section, ~30 new lines)
Validation:
- Editor diagnostics check passed (no syntax/errors in modified files)
-
/reloadand verify no errors (in-game verification pending) - Check each function in debug console (
/run print(SafeCompare(...))) (in-game verification pending)
Implementation Notes:
- Confirmed helper functions exist and are exported:
SafeCompare,SafeArithmetic,SafeToNumber,SafeToString - Refined
SafeArithmeticto support proper operand math with backward compatibility for legacy 3-arg usage - Unified wrappers so
SafeNumberusesSafeToNumberandSafeTextusesSafeToString
Time Estimate: 45 min
Difficulty: Easy
Risk: 🟢 LOW
Objective: Prevent "addon action forbidden" when reloading during combat Status: ✅ COMPLETE (2026-03-03)
What to Do:
- Create
Core/SafeReload.luawith:function addon:SafeReload() if InCombatLockdown() then addon:QueueOrRun(function() ReloadUI() -- Show confirmation popup end, { key = "SafeReload", type = "UI_RELOAD", priority = "NORMAL" }) else ReloadUI() end end
- Register in SimpleUnitFrames.lua
- Call from OptionsWindow.lua reload buttons
- Add to SimpleUnitFrames.toc load order
Files to Create:
- Core/SafeReload.lua (60-80 lines)
Files to Modify:
- SimpleUnitFrames.lua (register SafeReload method)
- Modules/UI/OptionsWindow.lua (call SafeReload on reload buttons)
- SimpleUnitFrames.toc (add Core/SafeReload.lua)
Validation:
-
/reloadin safe zone (should reload immediately) - Try reload during combat scenario (should queue for after combat)
- Verify no "addon action forbidden" errors
Implementation Notes:
- Core/SafeReload.lua already existed with full implementation
- Updated PromptReloadAfterImport() to use SafeReload
- Updated OptionsV2/Layout.lua reload button to prefer SafeReload
- All ReloadUI() calls now route through SafeReload when available
Time Estimate: 1 hour
Difficulty: Easy-Medium
Risk: 🟢 LOW (only called from option buttons)
Objective: Prevent crashes from malformed profile import strings
Status: ✅ COMPLETE (2026-03-03)
What to Do:
- Create
Modules/UI/ProfileValidator.luawith ValidateImportTree function - Check for:
- Correct data types (no functions, threads, userdata)
- Depth limits (max 20 levels deep)
- Node count limits (max 50k nodes)
- Integrate into core import validation path (
ValidateImportedProfileData) so all import handlers are protected - Show user-friendly error messages on failure
Files to Create:
- Modules/UI/ProfileValidator.lua (80-120 lines)
Files to Modify:
- SimpleUnitFrames.lua (call ValidateImportTree before payload unwrap/deep copy)
- SimpleUnitFrames.toc
Validation:
- Editor diagnostics check passed (no syntax/errors in modified files)
-
/reloadand test normal profile import (should work) - Try importing a corrupted profile string (should show error)
- Verify error message is clear to user
Implementation Notes:
- Added iterative
addon:ValidateImportTree()helper inModules/UI/ProfileValidator.lua - Enforces unsupported type rejection (
function,thread,userdata) in keys and values - Enforces limits: max depth 20, max table nodes 50000
- Detects cycles/repeated table references and blocks unsafe payloads
- Wired into
ValidateImportedProfileData()beforeUnwrapImportedPayload()so legacy + OptionsV2 imports are both protected
Time Estimate: 1 hour
Difficulty: Medium
Risk: 🟢 LOW (only adds validation, doesn't change success path)
Phase 1 Summary:
- Total Time: 3-3.5 hours
- Total Risk: LOW across all items
- Outcome: Cleaner codebase, better error handling, future-proof APIs
- Next: Move to Phase 2 after validation
Medium-effort, high-value enhancements. Better user experience.
Objective: Single accent color picker → all UI colors automatically update
Status: ✅ COMPLETE (2026-03-03)
What Was Implemented:
- ✅ Created color derivation functions in Theme.lua:
LerpColor(r1,g1,b1,r2,g2,b2,t)- Linear interpolation between colorsDarkenColor(r,g,b,factor)- Reduce brightness by factor (0-1)LightenColor(r,g,b,factor)- Increase brightness toward whiteGenerateAccentVariants(r,g,b)- Create base/soft/dark/light RGBA variants
- ✅ Built accent color cache system:
addon:UpdateAccentColor(r,g,b)- Updates cache and propagates to all UI colorsaddon:GetAccentColor()- Returns current accent RGB from cacheaddon.accentColorCache- Stores all color variants
- ✅ Added accent color picker to Options (Global/Theme section):
- Color picker widget in Registry.lua
- Saves to
db.profile.media.accentColor - Real-time UI refresh on color change via ScheduleUpdateAll()
- ✅ Integrated into reload flow:
- Accent color default in profile (SimpleUnitFrames.lua line 67)
- Color restoration in OnInitialize() (SimpleUnitFrames.lua line ~9940)
- Automatic restoration on /reload
Files Modified:
- Modules/UI/Theme.lua (added 100+ lines of color math at lines 665-790)
- Modules/UI/OptionsV2/Registry.lua (added color picker widget at line 3730+)
- SimpleUnitFrames.lua (added default at line 67, restoration at line ~9940)
Validation:
- Syntax validation passed (all 3 files: no errors)
- In-game test: Open options → Global/Theme tab → change accent color (Working ✅)
- In-game test: Verify all UI elements update (buttons, controls, text, backgrounds) (All elements update correctly ✅)
- In-game test: /reload and verify color persists (Color persists across reload ✅)
- Performance test: Rapidly changing accent color with no FPS drops or stutters (Smooth 60 FPS ✅)
Implementation Notes:
- Color derivation uses HSL-inspired math: darken/lighten adjust brilliance while preserving hue
- Soft color (reduced saturation variant) helps with UI contrast balance
- All THEME references update dynamically through cache layer
- Profile migration automatic for existing users (defaults applied on first load)
- Process is event-driven (no polling overhead)
Time Estimate: 2-3 hours (completed)
Difficulty: Medium
Risk: 🟢 LOW (all changes validated, no regression risk)
Objective: Search results now navigate to correct tab + scroll to section + pulse highlight
Status: ✅ COMPLETE (2026-03-04)
What Was Implemented:
- ✅ Scroll to Section — Auto-scrolls page to bring matched section into view
- Calculates section TOP anchor position relative to scroll content
- Uses SetVerticalScroll() to position section 50px from top
- Handles multi-anchor frames correctly (iterates all GetPoint() anchors)
- ✅ Pulsing Text Highlight — Matched control label pulses continuously
- Changes FontString color to accent color
- Uses C_Timer.NewTicker(0.5s) for continuous pulse effect
- Alternates between accent color and original color
- Pulse continues until search box cleared (backspace or ESC)
- ✅ False Positive Filtering — Eliminates duplicate page-level matches
- Search index contains both page-level (sectionKey=nil) and section-level entries
- Filters out page-level matches when section-level matches exist for same page
- Prevents "Failed condition check" false positives
- ✅ Cleanup on Clear — All pulse timers canceled when search cleared
- OnTextChanged handler detects empty search box
- OnEscapePressed handler cancels all active timers
- Restores all FontStrings to original colors
Files Modified:
- Modules/UI/OptionsV2/Layout.lua (scroll calculation + pulse system at lines ~425-495)
- Modules/UI/OptionsV2/Renderer.lua (section frame storage at lines ~607-610)
- Modules/UI/OptionsV2/Search.lua (false positive filtering at lines ~156-175)
Technical Details:
- WoW API Discovery: ScrollToChild() doesn't exist → used SetVerticalScroll(pixels) with manual calculation
- Frame Hierarchy: GetChildren() returns child frames; GetRegions() returns FontStrings/textures
- Anchor System: Iterates all GetPoint() anchors to find TOP anchor relative to pageContent
- Pulse Storage:
addon._searchHighlightedRegionsarray tracks all pulsing FontStrings for cleanup
Validation:
- Syntax validation passed (all 3 files: no errors)
- In-game test: Search for "health" → jumps to correct section (Working ✅)
- In-game test: Page scrolls to section position (Scrolling correctly ✅)
- In-game test: Matched label pulses continuously (Pulsing perfectly ✅)
- In-game test: Clear search (backspace) → pulse stops and color restores (Cleanup working ✅)
- In-game test: Press ESC to clear → pulse stops and color restores (ESC handler working ✅)
- In-game test: No false positives (page-level matches filtered ✅)
Implementation Notes:
- Deferred callback (0.1s) ensures page render completes before scroll/highlight
- Debug logging removed after validation (production-ready code)
- Pulse timer cleanup prevents memory leaks and orphaned timers
- Color restoration uses stored __searchOriginalColor RGBA values
- Search result filtering happens at query time (not render time)
Time Estimate: 1-2 hours (completed)
Difficulty: Medium
Risk: 🟢 LOW (all edge cases handled, cleanup robust)
Objective: Break OptionsV2/Renderer.lua BuildGUIPanel into smaller, testable functions
Status: 🔴 NOT STARTED
Implementation Strategy:
- Scroll to Section — Use pageScroll:ScrollToChild() to scroll section into view
- Visual Highlight — Tint section background briefly to show user where match is
- Control-Level Matching — Track which specific control matched (if applicable)
Files to Modify:
- Modules/UI/OptionsV2/Search.lua — Store control info in search results
- Modules/UI/OptionsV2/Layout.lua — Call scroll function on SetPage
- Modules/UI/OptionsV2/Renderer.lua — Store section frame references + add scroll-to function
Step-by-Step Implementation:
Step 2.2.1: Enhance search index to track control-level info
- Modify Search.lua so each search result includes closest parent section frame
- Track control index within section for precision matching
Step 2.2.2: Add section frame storage in Renderer
- When rendering sections, store frame reference on page content
- Store as addon._optionsV2SectionFrames[pageKey][sectionKey] = sectionFrame
Step 2.2.3: Implement scroll-to-result function
- Create addon:ScrollOptionsV2SearchResult(pageKey, sectionKey)
- Use pageScroll:ScrollTochild(sectionFrame) if available
- Add tint animation (highlight section for 1 second)
Step 2.2.4: Integrate into RunSearch
- After SetPage(), call scroll function with match data
- Verify no conflicts with existing navigation
Validation:
- Search for setting (e.g., "health color")
- Click result → should navigate to correct tab and scroll to section
- Section should highlight briefly to show where match is
- Verify existing search still works (no regressions)
Time Estimate: 1-2 hours
Difficulty: Medium
Risk: 🟢 LOW (enhancement to existing search, non-breaking)
Objective: Break up OptionsV2 page specs into separate builder files (code quality)
Status: ✅ COMPLETE (2026-03-04)
What to Do:
- Extract each OptionsV2 page into separate builder file under
Modules/UI/OptionsV2/Builders/ - Register builders in central registry (
addon._optionsV2Builders) - Route
GetOptionsV2PageSpec()through builder delegation first - Remove inline legacy blocks from Registry once all builders are stable
Files Created:
Modules/UI/OptionsV2/Builders/(new directory)Modules/UI/OptionsV2/Builders/*.lua(one per page)
Files Modified:
Modules/UI/OptionsV2/Registry.lua(builder delegation + all legacy branches removed)SimpleUnitFrames.toc(load builder files before Registry)
Completed Work:
-
CreditsBuilder.luaextracted -
TagsBuilder.luaextracted -
PerformanceBuilder.luaextracted -
ImportExportBuilder.luaadded (placeholder page, previously unimplemented) -
UnitsBuilder.luaadded (routes player/target/tot/focus/pet/party/raid/boss) -
GlobalBuilder.luafully extracted (standalone global page spec + helpers) -
CustomTrackersBuilder.luafully extracted (1159 lines: 6 sections, state management, all helpers) -
Registry.luabuilder delegation added withskipBuilderLookupfallback flag - Removed all inline legacy page branches from
Registry.lua(performance, tags, credits, units, global, customtrackers) -
SimpleUnitFrames.tocupdated with builder load order
Implementation Notes:
- CustomTrackersBuilder.lua contains complete standalone implementation (1159 lines):
- BuildMediaOptions helper (LSM font/texture integration)
- BuildCustomTrackersPageSpec() function with all sections (manage, layout, position, visibility, cooldown, entries)
- State management closures (ctState.selectedBarID, GetBars, GetSelectedBar, SetBarField, etc.)
- Dynamic entry button row generation (inline - / U / D controls)
- All 6 section control arrays preserved from original inline implementation
- Registry.lua now only contains builder delegation and defaults fallback (all inline page specs removed)
Validation:
- Syntax validation passed (CustomTrackersBuilder.lua and Registry.lua: no errors)
- In-game: all 14 pages render correctly
- In-game: all settings apply and persist
- In-game: Custom Trackers page fully functional (bar CRUD, entry management, all 6 tabs)
- In-game: search navigation still works across extracted pages
- In-game: no visual regressions / lua errors on
/reload
Time Estimate: 3-4 hours (completed)
Difficulty: Hard (large refactor)
Risk: 🟢 LOW (validated, non-breaking)
Objective: Adopt vertical sidebar tabs like QUI (visual overhaul)
Status: 🔴 DEFER to Phase 3
Reason: Largest change, requires careful UX testing
Phase 2 Summary:
- Total Time: 6-9 hours (or 12-13 with Task 2.4)
- Total Risk: LOW to MEDIUM
- Outcome: Better UX, client-friendly colors, easier code maintenance
- Blockers: None (all items independent)
- Next: Phase 3 visual polish after validation
High-impact visual improvements.
Objective: Unit frames render cleanly at all UI scales (75%, 100%, 125%)
Status: ✅ COMPLETE (2026-03-04)
- Study QUI's implementation (scaling.lua, lines 1-100)
- Create Core/PixelPerfect.lua with:
- GetPixelSize(frame) → physical pixel size
- Pixels(n, frame) → round to nearest pixel
- PixelRound(value, frame) → utility
- Cache screen dimensions on UI_SCALE_CHANGED
- Update all frame sizing in Units/ directory
- Update Theme.lua border creation
- Update Movers.lua position tracking
Files to Create:
- Core/PixelPerfect.lua (80-120 lines)
Files to Modify:
- Units/Player.lua, Units/Target.lua, Units/Pet.lua, Units/Focus.lua, Units/Tot.lua (sizing)
- Modules/UI/Theme.lua (border creation)
- Modules/System/Movers.lua (position tracking)
- SimpleUnitFrames.lua (cache screen dimensions)
- SimpleUnitFrames.toc
Validation:
- Screenshot unit frames at 75% UI scale (borders clean)
- Screenshot at 100% UI scale (borders consistent)
- Screenshot at 125% UI scale (no seams/gaps)
- Test window drag/resize (pixel-perfect positions preserved)
Time Estimate: 4-5 hours
Difficulty: Hard (touches many files, many edge cases)
Risk: 🟡 MEDIUM (visual regressions possible)
Value: 🟢🟢 HIGH (most visible improvement)
Phase 3 Summary:
- Total Time: 4-5 hours
- Total Risk: MEDIUM (visual testing critical)
- Outcome: Professional appearance at all UI scales
- Visual Impact: HIGH (users immediately notice improvement)
- Next: Phase 4 or community feedback
Objective: Unit frames render cleanly at all UI scales (75%, 100%, 125%)
Status: ✅ COMPLETE (2026-03-04)
What Was Implemented:
- ✅ Created Core/PixelPerfect.lua (342 lines)
- Core pixel math: GetPixelSize(), Pixels(), PixelRound/Floor/Ceil()
- Frame-aware sizing: SetPixelPerfectSize/Width/Height()
- Pixel-aligned positioning: SetPixelPerfectPoint(), SetSnappedPoint(), SnapFramePosition()
- Backdrop creation: SetPixelPerfectBackdrop() for exact N-pixel borders
- Texture snapping: ApplyPixelSnapping() using WoW 12.0+ APIs (SetSnapToPixelGrid, SetTexelSnappingBias)
- Smart scale utilities: GetSmartDefaultScale() (0.53 for 4K, 0.64 for 1440p, 1.0 for 1080p)
- Event system: UI_SCALE_CHANGED handler with cached screen dimensions
- ✅ Applied pixel-perfect sizing to frame creation via addon:ApplySize()
- ✅ Applied texture snapping to 9 StatusBar types (Castbar, ClassPower, Health/Power prediction bars)
- ✅ Integrated into Theme.lua backdrop creation
- ✅ Fixed initialization order (PixelPerfect now initializes after database setup)
- ✅ Added nil guards for early calls before frame spawning
Files Created:
- Core/PixelPerfect.lua (342 lines)
Files Modified:
- SimpleUnitFrames.lua (InitializePixelPerfect() call, SnapFrameToPixelGrid() helper, ApplySize() update, frame creation snapping)
- Modules/UI/Theme.lua (EnsureBackdrop() pixel-perfect integration)
- SimpleUnitFrames.toc (load order)
Validation:
- Static syntax/error validation passed (all 3 files: no errors)
- Fixed 2 critical initialization errors (ipairs nil guard, db nil guard)
- In-game validation:
/reloadsuccessful, no Lua errors - In-game visual test: Borders clean at 75% UI scale ✅
- In-game visual test: Borders clean at 100% UI scale ✅
- In-game visual test: Borders clean at 125% UI scale ✅
- In-game test: Window drag/resize preserves pixel alignment ✅
- Performance test: No FPS impact from pixel calculations ✅
Implementation Notes:
- Studied QUI's scaling.lua (487 lines) as reference implementation
- Pixel-perfect formula: pixelSize = 768 / (physicalScreenHeight * effectiveScale)
- Frame-aware calculation accounts for parent chain scaling via GetEffectiveScale()
- Event-driven system: UI_SCALE_CHANGED triggers screen dimension cache update + ScheduleUpdateAll()
- Smart defaults auto-detect display resolution for optimal UI scale (prevents blur)
- All StatusBar textures snapped for crisp rendering without sub-pixel artifacts
Time Estimate: 4-5 hours (completed)
Difficulty: Hard
Risk: 🟢 LOW (all edge cases handled, in-game validation complete)
Value: 🟢🟢 HIGH (professional frame rendering at all UI scales)
Phase 3 Summary:
- Total Time: 4-5 hours
- Total Risk: LOW (comprehensive validation completed)
- Outcome: Professional appearance at all UI scales (75%, 100%, 125%)
- Visual Impact: HIGH (users immediately notice clean borders and crisp textures)
- Status: ✅ COMPLETE
All Phases Complete: Phase 1, Phase 2, Phase 3 ✅
Work Completed Summary:
- Phase 1 (Quick Wins): 3 tasks complete (Safe Helpers, SafeReload, Profile Validation)
- Phase 2 (UI Improvements): 3 tasks complete (Accent Colors, Search Navigation, Modular Builders)
- Phase 3 (Visual Polish): 1 task complete (Pixel-Perfect Scaling)
- LibCustomGlow Integration (2026-03-06): Expanded glow style options for castbar non-interruptible, raid debuffs, and target selection (PIXEL/AUTOCAST/BUTTON/BORDER styles with UI controls in both OptionsV2 and legacy OptionsWindow)
Recommended Next Steps:
- Option A: Prepare v1.30.0 release (all core phases complete)
- Update CHANGELOG.md
- Tag release:
git tag v1.30.0 - Publish release notes
- Option B: Continue with Phase 4 (Infrastructure features)
- Task 4.1: Profile Migration Helpers (3-4 hrs)
- Task 4.2: Sidebar Tab UI Overhaul (6-8 hrs)
- Option C: Community feedback & top-up features
- Gather user feedback from Phase 1-3 work
- Polish based on gameplay testing
Large features that deserve dedicated sessions.
Status: 🟡 OPTIONAL
Objective: Users' profiles continue working across addon updates
Why Later:
- Needed only when schema changes happen
- Can add retroactively (no rush)
Status: 🟡 OPTIONAL
Objective: Vertical sidebar tabs like QUI (QUI reference: options/framework.lua, options/options.lua)
Why Later:
- Largest change (total UI redesign)
- Requires extensive UX testing
- Can be done after core features solid
- Task 4.3: Modular Cooldown System (8-12 hours) - 🔴 LOW PRIORITY
- Task 4.4: Advanced Aura Filtering (10-15 hours) - 🔴 LOW PRIORITY
- Task 4.5: Frame Preview Mode (6-8 hours) - 🟡 MEDIUM PRIORITY for Phase 5 polish
Status: All DEFER unless user demand justifies effort
Monday: Task 1.1 (API Version Compat - 30 min)
Tuesday: Task 1.2 (Safe Helpers - 45 min) + Task 1.3 (SafeReload - 1 hour)
Wednesday: Task 1.4 (Profile Validation - 1 hour)
Thursday: Validation & Testing
Friday: Code Review & Commit
Time Total: 3-4 hours
Risk: 🟢 LOW across all tasks
Pick Your Path:
Path A: UI Quality Focus (6-7 hours)
Week 2 Mon-Wed: Task 2.1 (Accent Colors - 2-3 hours)
Week 2 Thu-Fri: Task 2.2 (Search Nav - 1-2 hours)
Week 3 Mon-Tue: Task 2.3 (Modular Builders - 3-4 hours)
Path B: Defer Builders (2-3 hours)
Week 2: Task 2.1 + Task 2.2 only
(Save Task 2.3 for Phase 4)
Mon-Fri: Task 3.1 (Pixel-Perfect Scaling - 4-5 hours)
+ Testing (extensive screenshots at different UI scales)
Visual Impact: 🟢 HIGH (users immediately notice)
- Read relevant QUI reference code (links in RESEARCH.md)
- Create git feature branch (e.g.,
feature/api-compat) - Estimate time (add 20% buffer)
- List all affected files
- Follow existing code style (no reformatting)
- Add comments for non-obvious logic
- Test
/reloadfrequently - Verify no new Lua errors in debug console
-
/reloadaddon and verify no errors - Test in safe zone (no combat)
- Test in dungeons/raids (if applicable)
- Run
/SUFperf(verify no frame time spike) - Take screenshots (visual verification)
- Update WORK_SUMMARY.md
- Create commit with clear message
- Merge to main branch
- ✅ API version caching working
- ✅ Safe helpers added and used (no breaking changes)
- ✅ SafeReload prevents combat lock errors
- ✅ Profile validation prevents import crashes
- ✅ No performance regression
- ✅ Accent color system functional (single picker → all UI colors update)
- ✅ Search navigation works (click result → correct tab + scroll section)
- ✅ Modular builders reduce code complexity
- ✅ No visual regressions to options UI
- ✅ Frames render cleanly at 75%, 100%, 125% UI scales
- ✅ No blurry borders/lines
- ✅ Window drag/resize preserves pixel-perfect positions
- ✅ No performance regression (frame time budget consistent)
| Risk | Mitigation |
|---|---|
| Accent color system breaks existing theme | Keep existing Theme.lua functions as fallback |
| Pixel-perfect math incorrect at edge cases | Screenshot-test extensively at all UI scales |
| Search nav scrolls to wrong section | Hard-code section registry entries first |
| Profile validation too strict | Start with lenient checks, tighten gradually |
# Start feature
git checkout -b feature/NAME-FROM-TASK
git commit -m "Task X.Y: Description"
# After testing
git commit -m "Task X.Y: Fix issues from testing"
# Before merge
git diff main -- [affected files] # Review changes
# Merge to main
git checkout main
git merge feature/NAME-FROM-TASK --no-ff
# Tag release if completing phase
git tag -a v1.24.0 -m "Phase 1 Quick Wins Complete"RESEARCH.md: Full analysis with effort/value/risk assessments
QUI Code: See RESEARCH.md Section F for file paths
SUF Code: SimpleUnitFrames.lua (main), Modules/UI/ (options), Units/ (frames)
- Phase 1 is Self-Contained: All 4 tasks independent, can do in any order
- Phase 2 Builds on Phase 1: But not required (can skip Phase 1)
- Phase 3 Depends on Phase 2: Especially Task 2.3 (modular builders help with sizing)
- Phase 4 Deferred: Only tackle if users specifically request features or addon has time
Ready to start? Begin with Task 1.1: API Version Compatibility (30 min) ← Recommended first task