Skip to content

April's fool#1360

Open
dodoels wants to merge 21 commits intowowsims:masterfrom
dodoels:sim-replay
Open

April's fool#1360
dodoels wants to merge 21 commits intowowsims:masterfrom
dodoels:sim-replay

Conversation

@dodoels
Copy link
Copy Markdown

@dodoels dodoels commented Apr 1, 2026

Summary

image

Adds a Replay tab to the DetailedResults panel, positioned between the Timeline and Log tabs.

The tab uses the same shared resultsEmitter as Timeline and LogRunner — no separate simulation button is needed; the replay automatically populates after any sim run.

Playback stops and resets when the user navigates away from the tab.

Implementation

CombatReplay component (ui/core/components/detailed_results/combat_replay.tsx):

  • Extends ResultComponent, receives data via onSimResult() for full consistency with the rest of the results panel
  • Arena with Patchwerk boss silhouette, nameplates and HP bars that drain as damage accumulates
  • Spell cast ticker (last 10 casts) with DOM recycling and browser-level image preload cache to prevent reflows
  • Hit effects: flash, expanding ring, floating damage numbers rendered per-frame
  • CDM HUD: player name, cast bar, resource bars (all MoP resource types incl. Chi / Solar+Lunar Energy / rune segments), action icon grid with glow on recent casts
  • Playback controls: play/pause, 1x/2x/3x speed, scrubber, seek buttons
  • Wowhead native tooltips on spell icons via actionId.setWowheadDataset()

Other changes:

  • assets/img/boss_patchwerk.png — Patchwerk boss silhouette
  • ui/scss/core/components/detailed_results/_combat_replay.scss — dark-theme styles
  • I18n strings added for en and fr locales

Test plan

  • Run a simulation; switch to the Replay tab — scene appears with correct boss count and HP bars
  • Press Play — timeline advances, ticker updates, hit effects fire
  • Scrub and use seek buttons — frame renders correctly at any point
  • Navigate away from Replay mid-playback — playback stops and resets
  • Hover spell icons in ticker and action grid — Wowhead tooltips appear
  • Verify with multiple MoP specs that resource bars show correct type and colour

dodoels added 5 commits April 1, 2026 13:37
Adds a SimDaddy-style first-person combat replay visualiser as a
ResultComponent that reacts to the shared resultsEmitter — consistent
with Timeline and LogRunner.

Features:
- Arena with Patchwerk boss silhouette, floating nameplates and HP bars
- Spell cast ticker strip (last 10 casts) with DOM recycling and image
  preload cache to prevent layout reflows on each new spell
- Hit effects: flash, ring and floating damage numbers on boss
- CDM HUD: player name, cast bar, resource bars (MoP resource types
  including Chi, Solar/Lunar Energy), action icon grid with glow on cast
- Playback controls: play/pause, 1x/2x/3x speed, scrubber, seek buttons
- Stops and resets playback when the Replay tab is hidden

Made-with: Cursor
Dark-theme scene styles for the combat replay arena, ticker strip,
enemy cards, CDM HUD (cast bar, resource bars, action grid) and
playback controls.

Made-with: Cursor
Adds a 'Replay' tab between Timeline and Log. Instantiates CombatReplay
against the shared resultsEmitter; wires hide.bs.tab to stop playback
when the user navigates away.

Made-with: Cursor
@dodoels dodoels changed the title feat: add combat replay tab to detailed results add combat replay tab to detailed results Apr 1, 2026
@dodoels dodoels changed the title add combat replay tab to detailed results April's fool Apr 1, 2026
dodoels added 8 commits April 1, 2026 14:36
- Add combat_replay block to translation.schema.json (fixes CI test failure)
- Show active player buffs as small icons in CDM header row
- Show active target debuffs as small icons under enemy HP bar
- Wowhead tooltips on all aura icons via setWowheadDataset
- Deduplicated aura rendering with key-based reconciliation to avoid per-frame DOM thrash

Made-with: Cursor
- parseResult and buildScene now accept SimResultFilter
- Enemies rendered from result.getTargets(filter) so dropdown selection is honoured
- Hit effects skip targets outside the filtered set
- Debuff rendering maps card index -> encounter index via filteredTargetEncounterIndices
- Player entity and label resolved via result.getPlayers(filter)

Made-with: Cursor
…ps fire

tooltips.js (zamimg) hooks into <a href="...wowhead..."> elements.
All icon slots (ticker, action grid, buff/debuff) now use <a> elements
with setBackgroundAndHref (background-image + href) + setWowheadDataset,
matching the pattern used in metrics_table and timeline.

Made-with: Cursor
Aura logs are emitted as "[entity] gained [aura]" where entity is the
RECEIVER, not the caster. Debuffs on targets therefore have source =
target entity, not player entity. Calling fromLogs(logs, playerEntity)
was finding player-received buffs only and missing all target debuffs.

Fix: use the pre-computed UnitMetrics.auraUptimeLogs which correctly
uses each unit's own log subset and entity reference:
- players[0].auraUptimeLogs  -> player buffs
- filteredTargets[i].auraUptimeLogs -> per-target debuffs

Made-with: Cursor
Replaces flat flex row with a perspective-depth formation:
- Front row: ceil(n/2) targets, full size, bottom-aligned
- Back row: remaining targets, scale(0.62), pushed up 14%, brightness(0.6)
- All cards absolutely positioned so they naturally overlap
- Back row rendered first (lower z-index) so front targets overlap them
- Card width scales with target count to prevent overflow at any N

Made-with: Cursor
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
Comment thread ui/core/components/detailed_results/combat_replay.tsx Outdated
- Enemy cards: build with tsx-vanilla refs; track hp/debuff/hit layer in enemyCardDom[]
- Hit effects: makeHitEffectRoot as TSX; DocumentFragment + replaceChildren per target
- Hit rings: outcome classes + --bs-hit / --bs-crit (timeline-aligned)
- Resources: RESOURCE_PRIORITY const; JSX rows + replaceChildren (no innerHTML strings)
- Action grid: Map actionIconByKey instead of querySelectorAll
- Auras: fragment + ref-based <a> icons; replaceChildren
- Play/pause: Font Awesome fa-play / fa-pause class toggle
- formatReplayTime (renamed from fmt); player label ref
- encodeHTMLEntities() helper in utils.ts

Made-with: Cursor
Comment thread assets/img/boss_patchwerk.png Outdated
Comment thread assets/locales/en/translation.json Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
Copy link
Copy Markdown

@1337LutZ 1337LutZ Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please double check all color hex/rgba usages and replace them with --bs-* css vars

Comment thread ui/scss/core/components/detailed_results/_combat_replay.scss Outdated
const dmgLogs: DamageDealtLog[] = [];
const resourceLogs: ResourceChangedLog[] = [];

for (const log of result.logs) {
Copy link
Copy Markdown

@1337LutZ 1337LutZ Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified without typecasting:

for (const log of result.logs) {
			if (log.timestamp < 0) continue;
			if (log.isCastBegan()) castBeganLogs.push(log);
			else if (log.isDamageDealt()) dmgLogs.push(log);
			else if (log.isResourceChanged()) resourceLogs.push(log);
		}

const players = result.getPlayers(filter);
const playerEntity = players[0] ? new Entity(players[0].name, '', players[0].index, false, false) : null;

const castBeganLogs: CastBeganLog[] = [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add const actionMetrics = result.getActionMetrics(filter); above

const isRealSpell = (c: CastBeganLog): boolean => {
const id = c.actionId;
if (!id) return false;
if (id.otherId !== OtherAction.OtherActionNone) return false;
Copy link
Copy Markdown

@1337LutZ 1337LutZ Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add if (actionMetrics.find(m => m.actionId?.equals(id))?.isPassiveAction) return false to filter passive actions as they shouldn't show as "cast" spells

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants