-
released this
2026-09-07 22:10:37 -05:00 | 11 commits to main since this releaseAdded
-
The Item Import cards now show an item's shop card on hover, not just its
name. A row offering "Lich Bane -> Stormsurge" named the sequence and left
you to remember what Stormsurge costs, what it gives and what it does. The
tooltip now carries the price, the stat lines, and each passive or active as
its own block:Stormsurge - 2,800g 90 Ability Power 15 Magic Penetration 6% Move Speed Stormraider Dealing 25% of a champion's maximum Health within 2.5s applies Squall to them.Data Dragon ships that text as an HTML blob, so a new
gen:item-details
generator flattens it offline intosrc/shared/item-details/and the app
commits plain strings. Parsing at author time rather than in the renderer
means nodangerouslySetInnerHTMLover vendor markup and no parser in the hot
path of a hover -- and a tag the parser does not know fails the generator
instead of reaching a user as a literal<passive>mid-champ-select.The asset deliberately holds no item names: the builds artifact is the
naming authority, so the tooltip takes the name from the option it is drawn
for and only the detail from here. A renamed item therefore shows its current
name beside a slightly stale stat line rather than the reverse, and an item
the asset has never heard of degrades to exactly the old behaviour -- the bare
name.
Changed
- Item costs regenerated on Data Dragon 16.17.1, two patches on from the
16.15.1 extract the overlay's gold difference was using. Three prices had
moved (Black Cleaver 2700 -> 2800, Devourer's Emblem 3000 -> 3200), one id had
gone and one had appeared. Left alone, the app would have quoted two different
prices for the same item -- the new tooltip's and the gold difference's.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
released this
2026-09-06 18:59:16 -05:00 | 14 commits to main since this releaseFixed
-
Both in-game overlays could paint underneath League, which looked exactly
like a broken overlay and a dead scout hotkey. Caught live: mid-game, the
live-metrics overlay was nowhere on screen and Ctrl+Alt+S appeared to do
nothing — while the log showedoverlay.shownand threescout.toggleevents
firing correctly. Enumerating the windows explained it: both overlays were
visible, click-through, and still carried theWS_EX_TOPMOSTstyle bit, yet
Windows had dropped them below the game window in the actual z-order (the
live overlay sat at position 61, League's game window at 20). The style bit
only says which band a window belongs to; it does not hold its place in that
band, and nothing re-asserted the placement after the window was first shown.Both windows are now re-raised with
moveTop()(aSetWindowPos(HWND_TOP, SWP_NOACTIVATE), so focus stays with the game) the moment they are shown, and
a slow keeper re-asserts it every 3 s for as long as either is visible —
covering the demotions that happen mid-game on alt-tab, a client popup, or a
resolution change. Hidden and destroyed windows are skipped, so nothing runs
outside a game.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
released this
2026-09-06 11:05:27 -05:00 | 15 commits to main since this releaseFixed
-
The scouting report's lane arrows and the WEAK LINK badge no longer
contradict the card they sit on. Both verdicts were computed from ranked LP
and on-champ form only, while theROLEline right beneath them — recent win
rate and KDA at that position, across every champion — was fetched, rendered
and then ignored by the maths. So a 152 LP edge handed a favourable arrow to an
ally first-timing their pick at 33% in the role, against an enemy at 44%; and
the weak-link badge landed on the highest-LP-deficit ally rather than the one
actually losing their lane, even when a teammate's own role line said as much.laneVerdictandthreatScorenow take a third component fromroleStats,
scored the same way as on-champ form (win rate against a coinflip, discounted
by a squared ramp to the five-game sample floor) at 0.6 weight, because role
form is the broader read of the two. In practice it moderates a rank-only call
more often than it flips one — the case above now reads "even" — but it is the
only evidence available for a player with no history on their pick, which is
exactly when the old scoring was least defensible. The sample discount,
isLowSample, and the two components are now written once against a shared
SampledStatsshape rather than duplicated per section.
Changed
- The
ROLErow leads with its game count —6g · 55% · 3.10 KDA— and dims
itself with the same amber*the on-champ row uses when the sample is under
five games. Both rows are cut from the same ten-match request, and the role
line is the thinner of the two because it keeps only the games played at that
position, so a bare70%was routinely three games of noise presented with
more confidence than the on-champ number beside it, which had carried a
low-sample marker all along.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
released this
2026-09-06 09:16:02 -05:00 | 16 commits to main since this releaseFixed
- Champions already locked in by another player no longer appear in "Suggested Picks" or "Your Pool This Patch". An ally locking Briar top left Briar sitting in the pool list while the user was still picking jungle — a suggestion for a champion nobody can pick. Both recommenders exclude
session.locked, but that list was read only from a top-levellockedfield the live LCU never populates: a captured champ-select payload carrieslocked: []for the entire phase, and the locked pick actually lives on the cell's ownchampionId. Extraction now derives the list from both teams' cells (plus completedtype: 'pick'actions) whenever the explicit array is empty — the same fallback the ban list has needed sincebans.*turned out to be empty too. Knock-on effects: the defensive-ban list stops treating a locked ally's champion as a live hover, and the "picking has begun" fallback that reveals Suggested Picks in a ban-less lobby now actually fires.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Champions already locked in by another player no longer appear in "Suggested Picks" or "Your Pool This Patch". An ally locking Briar top left Briar sitting in the pool list while the user was still picking jungle — a suggestion for a champion nobody can pick. Both recommenders exclude
-
v4.5.4 — Dagger marker for assumed cooldowns
StableAll checks were successfulCI / build-and-test (push) Successful in 1m32sreleased this
2026-09-05 23:13:20 -05:00 | 17 commits to main since this releaseChanged
- The assumed-cooldown marker is a superscript dagger rather than a tilde —
4:14†. A dagger is the conventional typographic mark for "this carries a
caveat", which is precisely the claim being made, and it sits quieter beside a
clock than a tilde does. It still hangs off the time rather than the champion
name, because which champion used which spell is known exactly and only the
duration is inferred. No legend is printed.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- The assumed-cooldown marker is a superscript dagger rather than a tilde —
-
v4.5.3 — Compact assumed-cooldown marker
StableAll checks were successfulCI / build-and-test (push) Successful in 1m31sreleased this
2026-09-05 22:55:10 -05:00 | 18 commits to main since this releaseChanged
-
The Cosmic Insight caveat is now a single character. The overlay used to
mark assumed rows with a degree sign and print a° assumes Cosmic Insight
footnote beneath the list. On a panel that has to be read at a glance
mid-fight, that was a whole extra line explaining a distinction most of the
time nobody is acting on.The marker is now a
~on the clock itself —~4:14— which reads as
"approximately" on sight and needs no legend, so the footnote is gone
entirely. Putting it on the time rather than the champion name also puts it
where the uncertainty actually lives: the identity is known, the duration is
the guess.Nothing about the maths changed. Durations still assume Cosmic Insight
whenever an enemy runs an Inspiration tree, because the live API never exposes
minor runes for other players and an early timer is the safe error.
assumedCosmicInsightremains on the IPC message and in the logs.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
v4.5.2 — Chat ping parsing fixes
StableAll checks were successfulCI / build-and-test (push) Successful in 1m30sreleased this
2026-09-05 22:43:10 -05:00 | 19 commits to main since this releaseFixed
-
Chat pings were dropped from 10:00 game time onward. Tesseract routinely
splits a two-digit minute with a stray space, reading13:03as1 3:03—
3 of 11 lines in one measured live capture. The timestamp pattern required the
separator to follow the minute digits immediately, so every one of those lines
failed to match and was discarded.The failure was invisible in the worst way: a dropped line is indistinguishable
from a line that was never a ping, so nothing logged and nothing surfaced. It
also hid behind early-game testing — a clock like00:13has a single minute
digit and survives, which is exactly why the first verified pings (Vex Flash at
0:13 and 0:20) worked while a later one did not.The digit groups now admit internal spaces and strip them before the value is
read, with the seconds still required to be exactly two digits so a greedy
match cannot run into the sender's name. Regression tests use verbatim
tesseract output rather than idealized strings. -
The verbose ping phrasing was dropped. League emits more than one wording,
and both turn up in the same game one second apart:06:28 JRendar (Amumu): Malphite Flash 06:28 JRendar (Amumu): Cho'Gath used FlashEverything before the spell was treated as the champion name, so the second
line asked the roster for a champion called "Cho'Gath used" and silently
dropped a real ping — visible on screen as one tracked Flash where two were
called. Connective words (used,uses,has,just) are now stripped from
the end of the champion candidate, never the start, so a champion whose name
legitimately contains one is unaffected.
Changed
- OCR latency measured at ~900ms per pass against a 2s poll, so the cadence has
room and is unchanged. Worth recording because the wrong diagnosis here was
tempting: chat lines fade after ~10s, which makes "we polled too slowly" a
plausible-sounding but incorrect explanation for a missed ping.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
v4.5.1 — Multi-word summoner spell names
StableAll checks were successfulCI / build-and-test (push) Successful in 1m31sreleased this
2026-09-05 22:23:52 -05:00 | 21 commits to main since this releaseFixed
-
Multi-word summoner spell names in chat pings. The parser assumed a spell
name was always the payload's last single word, which is wrong twice over.
Teleport is renamed Unleashed Teleport once it upgrades, so a ping on it
after that point never resolved at all. And Smite's jungle forms broke the
split the other way: a real line,13:09 JRendar (Evelynn): Riven Unleashed Smite, parsed as a champion called "Riven Unleashed" using "Smite" rather
than as Riven using "Unleashed Smite".Both halves of the payload can now be multi-word. The parser walks candidate
spell suffixes longest-first and accepts the first split where the champion
and the spell both resolve against their vocabularies — requiring both is
what stops a bad split from inventing a champion that does not exist. The
upgraded forms are listed explicitly (Unleashed Teleportat the same 240s;
Chilling/Challenging/Unleashed/Primal Smite), so the Smite variants
now resolve and are then cleanly rejected as charge-based instead of
mis-splitting.Found by reading a live game's chat rather than a bot game's: the only spell
ping that had occurred was an upgraded Smite, and it would have been dropped
for the wrong reason.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
v4.5.0 — Enemy summoner-spell cooldowns
StableAll checks were successfulCI / build-and-test (push) Successful in 1m32sreleased this
2026-09-05 21:49:40 -05:00 | 22 commits to main since this releaseAdded
-
Enemy summoner-spell cooldowns in the in-game overlay, driven by the chat
lines your team's scoreboard pings post. Holding Tab and clicking an enemy's
summoner spell writes02:19 Name (Champ): Pantheon Flashto team chat; the
overlay now reads that off the HUD and counts the spell down.Chat is the only signal available. Riot's Live Client Data API publishes no
summoner-cast events and no champion positions, and the Tab scoreboard shows
no enemy cooldowns, so nothing can detect a Flash automatically — a teammate
still has to ping it. What is automated is the duration, which is the part
every manual tracker gets wrong.Three properties of the chat line carry the design. It timestamps itself
with the game clock, so OCR latency is irrelevant — a line read eight seconds
late still yields an exact remaining cooldown, and there is deliberately no
freshness gate (unlike the CS/clock fusion, which has one). That timestamp
also dedupes: the same line is re-read every poll while it sits on screen,
andchampion|spell|timeis stable across those reads. And both fields come
from closed vocabularies — five enemy champions, nine spell names — so
every parse is validated against a known set rather than trusting raw OCR,
which is what makes fuzzy matching safe (Panlheon Fiashresolves; noise
does not). -
Haste-aware durations. Two sources are folded in, and they are not equally
knowable. Ionian Boots of Lucidity (+10) is observed —itemsis
published for every player on both teams, across the base, Arena and Classic
Rift id blocks. Cosmic Insight (+18) is assumed: the live API exposes
only the keystone and the two tree names for other players and never the minor
runes, so the rune is inferred whenever Inspiration appears in either tree.
The assumption is deliberately pessimistic — a timer that expires early is
safe, one that expires late gets you killed — and the overlay marks those rows
with a°and a footnote so an assumed number is never mistaken for a
measured one. Flash therefore reads 5:00, 4:33, 4:14 or 3:54 depending on what
they have: a 66-second spread.Remaining time is derived per snapshot from current haste rather than stored
as a deadline, so an enemy who buys Ionian Boots while Flash is down has the
running countdown shorten itself the moment the boots appear in their
inventory — which is what the game actually does.
Changed
LivePlayerSchemanow carries the payload'srunesandsummonerSpells
blocks (both optional, matching the schema's deliberately lenient posture).- The chat OCR reader thresholds on the value channel (
max(R,G,B)) rather
than the CS reader's luminance. Pure red has a luminance of 76, below the
existing threshold of 130, so a luma pass would have erased exactly the field
that names the champion. regions.jsongains achatbox, calibrated on 3440x1440. It is optional in
the schema, so an older calibration file still loads and simply leaves the
tracker idle.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
-
released this
2026-09-05 20:36:44 -05:00 | 23 commits to main since this releaseAdded
-
A "Refresh data now" button in the settings panel. Published artifacts are
cached and only re-fetched when that copy is older thancacheTtlHours(24h)
or describes a different patch. That check is not a launch check, so
restarting the app does NOT re-fetch a cache that is merely a few hours old,
andcacheTtlHourshas no in-app control by design — which left deleting
files from%APPDATA%or hand-editingsettings.jsonas the only overrides.
The window this closes is narrow but real: the crawler publishes once a night
at 07:00, so the morning after, yesterday evening's cache is still inside its
TTL and the app will not go looking.The button force-refreshes every artifact — benchmarks, synergies, counters
and tiers, runes, item builds, Classic Rift items, damage splits — and reports
what landed.forceskips the within-TTL shortcut and nothing else: a forced
fetch that fails still falls back to the cached copy, because a manual refresh
is no reason to leave champ select with nothing. The refreshers run
sequentially rather than in parallel, since these are up to ~9.5 MB each
against one small API and the automatic path spreads them across a session.The two Classic Rift files cannot by themselves make the result look broken.
Their producer pass is opt-in and the mode is limited-time, so a 404 is their
normal state, and reporting that as a failure is how a status indicator gets
ignored. -
A champion in a pool that its roster does not have is now marked. Pool
chips are matched against the roster's own champion list, and one with no
match is drawn with a dashed border and a title saying it is ignored. The
live and Classic Rift pools hold the same champion names against different
kits, so a name carried into the classic pool that Classic Rift does not have
was silently dropped by the pipeline while still looking configured in the
panel. Only applied once the client has actually listed champions — the list
is empty before the LCU connects, and striking through a whole pool on a cold
start would be worse than saying nothing.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-