• v3.9.0 cdcadff8be

    v3.9.0
    All checks were successful
    CI / build-and-test (push) Successful in 1m47s
    Stable

    joeyr released this 2026-07-27 20:51:18 -05:00 | 31 commits to main since this release

    Changed

    • Rune pages now come from the nightly crawler instead of being scraped during
      champ select.
      Recommended runes were the last thing this app fetched from
      op.gg at the moment it could least afford to: lock-in gives you about thirty
      seconds, the request queued behind stats and tier-list fetches on the shared
      rate limiter, and the result was cached in memory only — so every restart
      re-scraped every champion you had looked at.

      lol-companion-data now crawls those same pages nightly, off the same
      tier-list index it already fetches for counters, and publishes
      data/champion-runes.json. Lock-in reads it out of memory.

      op.gg stays wired as the fallback and nothing about the feature changes when
      it is used.
      A miss for any reason — the artifact not fetched yet, a patch
      mismatch, a champion op.gg does not list at that role — falls straight through
      to the scraper, exactly as before. The artifact is refused off-patch
      (servesOffPatch: false), because a recommended build is a claim about
      this patch's meta and the crawler is a night behind on patch-drop morning.

      The published file stores board rows as bare perk ids against a shared perk
      dictionary rather than repeating names and icon URLs on every option: measured
      over the same data, 212 KB against 1.9 MB. Which rune each row picked is
      derived positionally from selectedPerkIds — deliberately not by testing
      membership, because stat shard ids repeat across rows (5008 in rows 1 and 2,
      5001 in rows 2 and 3) and a membership test would highlight two shards where
      the page picked one.

      Perk hover descriptions are unaffected. They come from the running client's
      perk catalog over the LCU, which a headless crawler has no access to, so they
      are still attached on this side for both paths.

    • The champ-select board no longer tells you what to build. Each team's
      damage rollup used to end in an instruction — "Mostly AP → build MR". The same
      rollup renders for both columns, and that advice is only ever right about one
      of them: under YOUR team it read as "your team is AP-heavy, so build MR",
      which is backwards. The headline now names the composition and stops there
      ("Mostly AP"), which is true of whichever column you are reading. The scouting
      report's rollups carried the same line and lost it for the same reason.

    • Enemy lane dropdowns state the lane outright. They used to be prefixed
      with their provenance — "Guess · Jungle", "Auto · Support" — which spent the
      widest label in the row on a qualifier, clipped under the dropdown arrow at
      the longest lanes, and told the reader something the row's position already
      told them. The dropdown now reads "Jungle". The lane it defaults to is also
      dropped from the list below it, so the open menu no longer offers the same
      lane twice.

    • "Support" is now "Utility" on the board, matching the role name the ally
      column has always shown. The off-role tier tag follows (SUPUTIL). Other
      surfaces are untouched: the settings panel and the rune/item import headings
      still say Support, and imported item-set names (LoLC: Lux Support) keep
      theirs so already-imported sets are not orphaned in the client.

    Removed

    • Per-champion damage bars on the champ-select board. Ten of them, one per
      cell, restated in ten thin bars what the two team rollups above them already
      say in words — and the team number is the one a player actually itemises
      against. The rollups stay. The per-player bar is unchanged on the scouting
      report, where a single player's profile is the point of the surface.

    Fixed

    • The two team columns line up row for row again. The ally column renders
      its role as plain text and the enemy column as a dropdown, which is several
      pixels taller, so the two sides drifted further apart with every row — by the
      middle lane they were visibly offset, in a layout whose whole purpose is
      reading TOP against TOP. Both sides now reserve the same height for that line,
      and a cell with no tier badge (an unfilled lane, or a champion op.gg has no
      data for) holds its badge row open instead of collapsing it, so the columns
      stay aligned mid-draft as well.
    Downloads