# Cadence

Timeline-driven reminders for your healing cooldowns. Personal only — nothing is
sent to your group, and nothing is announced in chat.

## Install

Copy the `Cadence` folder into:

```
World of Warcraft/_retail_/Interface/AddOns/Cadence
```

Then fully restart the client — `/reload` does not pick up a newly installed
addon. Open it with `/cadence` (or `/cdn`), which toggles the window. Escape
closes it, and you can drag it by the title bar.

## The timeline

One row per ability, names down the left, pull time across the top. Every cast of
Tranquility sits on the Tranquility row, so you read a plan as a handful of lines
rather than as a scatter of icons. Each row gets its own colour.

Row order is yours. A new ability lands at the bottom, and after that nothing
moves unless you move it — retiming a cue so it becomes the first thing in the
fight does not promote its row. **Drag a row name** up or down to reorder; the
other rows slide aside and a band shows where it will land. The order is saved
with the plan, and an ability you delete keeps its slot in case you put it back.

A cue is drawn as a bar spanning the time it is actually on your screen — from the
head of its countdown to the end of its hold — with a bright cap on the exact
moment it fires. That makes overlap visible, which is most of what a healing plan
is about. Short bars are widened to stay clickable, so the bar is the approximate
span and the cap is the precise answer.

Zoom with the +/- buttons. The wheel walks the rows; hold Shift and it walks the
clock. The bars at the edges do the same.

- **Drag** a cue along its row to change its time. The cursor holds the moment it
  fires, not the head of the countdown. The live time shows above the bar, snapped
  to half a second — hold Shift for exact placement.
- **Left-click** a cue to enable or disable it. Disabled cues grey out.
- **Left-click a row name** to toggle every cue for that ability at once.
- **Right-click** a cue for edit, enable/disable, duplicate and delete.
- **Hover** either for the exact time, note and countdown length.

The window resizes from the grip in the bottom-right corner, and remembers its
size and position. The timeline redraws as you drag.

Boss-timer cues have no pull time, so they sit in their own strip beneath the
rows with the same click behaviour.

## Preloaded bosses

The boss dropdown ships with the eight Venomous Abyss encounters in raid order:

1. Nek'zali the Soulcoiler
2. Entombed Sentinels
3. Vashnik the Malignant
4. The Lost Explorers
5. Sszorak
6. The Twin Fangs
7. The Coiled Altar
8. Ula'tek

You can build and import plans for any of them before you have pulled them.

They are preloaded **by name**, not by encounter ID. Blizzard's DungeonEncounterID
values are not published anywhere I would trust, and a wrong one means a boss
whose cues never fire — worse than no entry at all. So an unpulled boss uses a
placeholder key and is marked *not pulled yet* in the list.

The first time you engage it, Cadence reads the real ID from `ENCOUNTER_START`,
matches it by name, and moves your plans across. If you had already built plans
under the real ID, the two are merged rather than one replacing the other.

The Twin Fangs is the exception: its ID (3421) came from a real plan export, so it
is bound from the start.

Nothing else is preloaded. Other bosses appear only after you pull them, and only
if the pull happened in a raid — dungeon and scenario encounters fire the same
event and would otherwise bury the roster. A boss you have already made plans for
stays tracked wherever you pull it.

**Right-click a boss in the dropdown** to remove it, or use **Plans > Forget this
boss**. It refuses while
that boss still has reminders, so nothing is lost by accident. Venomous Abyss
bosses come back, since they are part of the shipped roster.

`/cadence bosses` lists what is loaded and which IDs are still placeholders.

## Plans

Each boss holds any number of named plans — heroic and mythic, a split-raid
variant, a version you are trying out — picked from the **Plan** dropdown beside
the boss selector. Only the active plan runs, and only it is shown on the timeline.

The **Plans** button covers new, rename, duplicate and delete. Deleting the last
remaining plan empties it rather than removing it, so a boss always has somewhere
to put reminders.

Tag a plan with a difficulty under **Plans > Use for difficulty** and Cadence
switches to it automatically at the pull. A structured plan export carrying
`Difficulty:Heroic` is tagged on import, so importing your heroic and mythic
strings gives you two plans that select themselves.

Imports never overwrite each other: a string naming a plan that does not exist
creates it, and re-importing the same string updates that plan in place. Share
strings carry the plan name, so an exported plan lands under its own name on
someone else's machine.

Plans you saved before this existed are folded into one called **Default** on
first login. Nothing is discarded.

## Quick start

1. Pull the boss once. Cadence records its name and encounter ID, and it appears
   in the **Boss** dropdown.
2. Add reminders by hand, or hit **Share or import** and paste a timeline.
3. Hit **Move the anchor**, drag the cue where you want it, then lock it.
4. Hit **Test run** to hear it before you rely on it.

## The upcoming list

A separate movable window listing what is still ahead of you, next at the top,
with a countdown to each. An entry falls off the moment its cue lands, so the top
row is always the next thing you have to do. The next entry is bright; the rest
fade back so the order reads at a glance.

It appears when a fight starts and hides when the list empties. Both trigger
types feed it, so a boss-timer cue joins the list as soon as its bar starts.

Run `/cadence queue` to show a sample you can drag into place, then run it again
to dismiss. Row count and an on/off switch are in the panel under **Upcoming
list**; beyond that row count the title shows how many more are pending.

## How the timing works

Two trigger types per reminder:

- **After the pull** — fires at a fixed time into the fight, measured from
  `ENCOUNTER_START`. This is the one you will use most.
- **On a boss timer** — fires relative to a BigWigs or DBM bar. Pick the ability
  from the dropdown, set an offset (`-4` = four seconds before the cast lands),
  and which cast (`1` for the first, `0` for every one). Falls back to nothing if
  no boss mod is loaded, so keep pull-time reminders as your backbone on
  progression.

The ability list is learned, not shipped: every bar a boss mod starts during a
pull is recorded against that encounter, along with how long the bar ran and how
many times it fired. So the dropdown is empty until you have pulled the boss once
with BigWigs or DBM loaded, and it only ever offers abilities that actually
appeared in your fight. You can still type the text by hand.

Boss mods number repeat casts — `Venom Nova (2)`, `Venom Nova (3)` — and those
collapse into one entry rather than filling the list with near-duplicates. The
count is what **Which cast** is for. A boss remembers at most 200 distinct
abilities, which no real encounter comes close to.

Each reminder has a countdown length. The cue appears that many seconds early,
counts down, then flips to **NOW** with a sound.

A countdown cannot start before the fight does, so it is capped at the cue's own
time. A cue at 0:00 has no run-up and fires on the pull with no countdown at all,
which is what you want for lust; one at 0:03 counts three, not five. Boss-timer
cues hang off a bar rather than the pull, so they keep whatever you gave them.
The timeline tooltip and the reminder dialogue both show the countdown a cue will
actually get, not the one it asked for.

**Test run** compresses the plan so you are not waiting six minutes, but it steps
through distinct *times*, not individual reminders — so cues sharing a time still
arrive together and you can see the stack you will get on the pull. `/cadence test
real` plays the plan at its true timings if you want the genuine article.

Cues that come up at the same moment are batched onto one timer, so they appear
in the same frame and stack down the screen in the order they will be needed
rather than racing each other. Two reminders with the same time but different
countdown lengths appear apart and land together, which is what you want when one
needs a longer warning.

A new cue joins the bottom of the stack. When one has had its moment it hands its
slot over immediately and fades where it stood, so everything below it moves up
straight away rather than waiting under an invisible frame.

The stack limit only ever retires cues that have already fired. A cue still
counting down is never dropped — if six of them overlap, all six show and the
stack simply grows. Cues are driven by the absolute clock rather than by the timer
that revealed them, so a countdown that appears a frame late still fires on time.

## Importing

Open it with the **Share or import** button, or `/cadence import` directly.
Click the dark box, paste with Ctrl+V, then hit **Import**. **Export this boss**
fills the same box with a share string and selects it for Ctrl+C.

It takes any of these and works out which it got:

- A `CDNC1!…` string exported from Cadence — restores everything, including
  boss-timer anchors.
- Anything with times in it — a Lorrgs timeline, an MRT note, a list you typed.
  It reads `1:45`, `01:45`, `1:45.3`, `[1:45]`, `{time:1:45}`, `{time:105}`, `90s`,
  and comma-separated runs. Extra arguments inside a `{time:…}` token are ignored
  rather than dragged into the label.

Spells are identified three ways, in order of how much Cadence trusts them: an
explicit `{spell:740}` token or a spell link pasted out of chat; the spell's name
appearing in the row; then the heading above the row.

That last one is what makes the Lorrgs layout work, where the cooldown is named
once and each row underneath is a time and a player. The rows take the ability
from the heading, and the player's name is kept as the cue's note — so a row
reading `1:45  Ishnu` becomes Tranquility at 1:45, noted for Ishnu, not a cue
called "Ishnu".

A heading that is a section title rather than a spell — "Healer Cooldowns" — is
never used as an ability, so a row under it that Cadence cannot identify keeps its
own text. Anything unmatched still works as plain text.

Tick **Replace what's already there** to overwrite the boss instead of appending.

## Sounds

Cadence ships with a bundled voice pack: 126 clips covering healer cooldowns
across all six healer specs, other common raid cooldowns, and a set of generic
alerts you can assign to any reminder.

**Automatic.** When a cue fires, Cadence looks up the cooldown's name in the
voice pack and plays that clip. No configuration needed: Tranquility plays the
Tranquility clip, Power Word: Barrier plays the Barrier clip, and so on.

The fallback chain is: bundled clip → the reminder's own custom file → your
global default file → the built-in blip. You can override any cue from the
reminder editor by setting a custom path, or silence it entirely with the Silent
checkbox.

**Picking sounds in the editor.** The **Browse** dropdown in the reminder editor
lists the bundled clips grouped by spec. Choosing one from the list plays it and
fills in the path. Because these files ship with the addon the path is always
valid — no hunting through your WoW folder.

**Custom files.** Type or paste any absolute path into the sound field in the
editor. The file must be a `.ogg` or `.mp3` inside your World of Warcraft folder.
Paths from other addons (DBM, BigWigs) work fine. Hit **Test** to hear it before
saving.

**Generic alerts.** The following labels are included and can be typed directly
as a reminder's label or assigned as a sound:

- `Healing cooldown ready`
- `Cooldown ready`
- `No cooldowns left`
- `Use it now`
- `Incoming damage`
- `Save your cooldown`
- `Rotate cooldowns`
- `Damage reduction active`
- `Barrier down`
- `Tranquility incoming`

**Adding clips.** Drop a `.ogg` file into the right subfolder under
`Cadence/Sounds/` and add one line to `Media.lua`. No other changes needed:
the dropdown rebuilds from the table on every open.

## Colours

The interface uses a Horde palette — blood red, black and banner gold — defined
once in `ns.COLORS` in `Core.lua`. Change the values there and everything follows:
windows, timeline markers, the on-screen cue, the upcoming list and the chat
prefix. There are no colour literals scattered through the other files.

## Commands

| Command | Does |
|---|---|
| `/cadence` | Toggles the window |
| `/cadence test` | Plays the selected boss's cues back, compressed |
| `/cadence test real` | Plays the plan at its true pull times |
| `/cadence stop` | Stops a running test |
| `/cadence unlock` / `lock` | Moves the anchor |
| `/cadence stop` | Clears anything currently running |
| `/cadence import` | Opens the share and import window |
| `/cadence queue` | Previews the upcoming list so you can place it |
| `/cadence voice on` / `off` | Turns spoken cues on or off (no panel control) |
| `/cadence voice` | Reports why the voice is or isn't working, and tests it |
| `/cadence voice cycle` | Speaks through each TTS destination so you can find one |
| `/cadence voice 2` | Locks in destination 2 |
| `/cadence debug` | Prints what loaded, for when something is missing |

## If you hear no voice

Run `/cadence voice`. It reports whether the SpeakText API exists, how many
voices the game can see, which one Cadence picked, and your volume and rate — then
speaks a test line and tells you what went wrong if it could not.

**If it reports voices and still says nothing**, the speech is reaching a device
you are not listening to. WoW plays TTS through the voice chat audio path, not
the sound effects path, so game audio can be fine while speech is silent:

1. Options > Social > Voice Chat — enable voice chat and set **Output Device** to
   the headset or speakers you actually use.
2. `/cadence voice cycle` speaks a numbered line through each TTS destination,
   three seconds apart. Lock in whichever you hear with `/cadence voice 2`.

Cadence defaults to the queued destination, which is the most widely reliable,
but the right one varies by setup.

**If it reports no voices**, none are installed. Voices come from the operating
system:

- **Windows** — Settings > Time & Language > Speech > Manage voices
- **macOS** — System Settings > Accessibility > Spoken Content > System Voice

Install one and restart WoW; the game reads the list at launch. There is also a
**Test** button beside the voice dropdown in the panel.

## Sound files instead of speech

Speech has no panel controls — it never worked reliably enough to earn them.
`/cadence voice on` enables it and `/cadence voice` diagnoses it. Sound files are
the supported path and replace it entirely. `PlaySoundFile`
goes out through the normal sound channels rather than the voice chat path, so it
works where `SpeakText` is silent.

**Play a sound on cues** is the global switch, on the main panel. Everything
per-reminder is in the reminder dialogue.

- **Every reminder starts on the default.** A new cue leaves its sound blank,
  which means it plays whatever the default is. Change the default and every cue
  still on it follows, with no editing.
- **Give one cue its own clip** by filling the field, picking from **Browse**, or
  pressing **Test** to hear what it would play. **Use default** puts it back.
- **Silent** switches sound off for that one reminder. It still shows on screen
  and in the upcoming list, it just makes no noise. Silence wins over a file set
  on that reminder.
- **Set as default** makes the current file the default for every cue that has
  not been given one. It plays the file first and refuses to save a path the game
  cannot open. `/cadence sound <path>` does the same from chat.
- **Browse** — the dropdown beside each sound field lists every sound registered
  by an installed addon, grouped by source: BigWigs, DBM, DBM countdown packs, and
  anything else. Picking one fills the path and plays it.
- Drop your own files in `Cadence/Sounds/`. Paths are relative to your World of
  Warcraft folder and need double backslashes.

### What the browser can and cannot see

WoW gives addons no way to read the filesystem — nothing can list the contents of
a folder. The browser lists what other addons have registered in memory, via
LibSharedMedia (BigWigs, DBM and WeakAuras all register their sounds there) and
DBM's countdown pack table. So:

- If you have none of those installed, the list is empty and you type paths by hand.
- A voice pack that keeps its clips private won't show individual sounds. Those
  packs still appear under **Voice pack folders**, which fills in the folder so you
  only have to complete the filename. The Test button tells you if you got it right.

`/cadence sound list` reports what was found and which packs are installed.

Menus that hold submenus never scroll — a scrolling parent draws its children
over itself. Only the lists at the end of a branch scroll, and the spell picker is
at most two levels deep.

Nothing is ever truncated: every registered sound appears in the menu. Long menus
scroll, and a group of more than 60 splits into labelled runs of 40 — so a
registry of several hundred sounds stays browsable without a wall of entries.
Scrolling also applies to the boss list, the spell picker and its per-spec
submenus, and the learned ability list. The scroll cap comes from your screen
height, so a menu never grows past roughly half the window.

A broken path falls through to the built-in blip and says so once, so a typo
never leaves a cue silent.

## If the window does not open

Run `/console scriptErrors 1` then `/reload` — Lua errors are hidden by default,
so a broken addon looks like an addon that does nothing. Then `/cadence debug`
reports which pieces came up.

The window is a plain frame, not a Blizzard Settings canvas, because canvas
registration is the part of this addon most exposed to API changes and it fails
silently when it breaks. Settings registration is still attempted and adds an
**Open Cadence** button to the interface options, but nothing depends on it.
Display, schedule and options each start independently, so one failure cannot
take the other two down.

## Verify these on your machine

Three things are written defensively but should be checked against your live
client before you trust them on progression:

1. **`## Interface: 120100`** in the .toc. If the client flags the addon as
   out of date, put your actual build number there.
2. **Boss-mod hooks.** BigWigs `BigWigs_StartBar` and DBM `DBM_TimerStart` are
   wrapped in `pcall`, so a changed signature degrades to "boss-timer reminders
   never fire" rather than an error. Test one before relying on it.
3. **Spell IDs** in `Data.lua`. Anything Blizzard has renumbered still appears in
   the picker labelled `Spell 123456` rather than vanishing, so you can see what
   broke.

## Label overrides

`ns.SPELL_LABELS` at the top of `Data.lua` renames a spell wherever it appears —
picker, list, on-screen cue, and the spoken line:

```lua
ns.SPELL_LABELS = {
    [370564] = "Release Stasis",
}
```

An override beats whatever the client returns. That is deliberate: `370564` is
the Stasis release, and on a client that names it plain "Stasis" both halves of
the pair would read identically in a plan. Add your own entries the same way.

On login, any saved reminder still carrying a placeholder label (`Spell 370564`,
a bare number, or the client's own name) is updated to the override. A label you
typed yourself is never overwritten.

## Cooldowns by spec

`Data.lua` covers all seven healing specs plus a shared **Raid utility** group
(lust, combat res). Groups are keyed by spec rather than class, because
Discipline and Holy don't share a list.

Your own spec's cooldowns sit at the top of the spell picker; the rest are under
**Other specs**. Every group is loaded on every character, so name matching works
on an imported plan written for a different healer — a Paladin importing a
Shaman's timeline still gets icons and clean spoken names.

Spec is detected via `GetSpecializationInfo`. If that fails it falls back to your
class, and on a non-healer the picker is empty rather than guessing. You can
always type a name or a raw spell ID instead.

## Why it works this way

Since Secret Values, addons can't read cooldown, aura or health state in combat,
so a reminder can't ask "is Tranquility actually up?" or "is the raid hurt
enough?". What is still permitted is knowing the time and reacting to encounter
events, which is what boss mods do and what this addon does. Everything here is
a schedule you wrote, played back to you.
