Reverse-engineered site reference

Sim League Nirvana — Data Field Guide

Where every stat lives on simleaguenirvana.com, how each page is shaped, and the quirks that bite. Built from the scrapers behind the SLN Stat Book and verified against the live site.

Basewww.simleaguenirvana.com
LeaguesSLN · NDL (/NDL/)
Seasons43 (1996–2039)
Teams / season~29
Encodinglatin-1
01

What the site is, and how to reach it

A classic static-HTML sim-league site. Two leagues share one layout; every stat page is a plain .htm/.html file you can fetch directly.

Two leagues, same skeleton. The main league SLN lives at the site root; the developmental league NDL mirrors the exact same page layout under a /NDL/ prefix. The same parsers work on both.

The frameset trap

On-site navigation runs through JavaScript <frameset> pages (e.g. index2.htm), so the browser URL bar never changes as you click around. Don't scrape by watching the address bar — go straight to the underlying files below. The site's own one-leader-per-category playercareerrecords.htm is only reachable through that frameset nav.

NDL — no history NDL publishes the current season only. Every /NDL/history/…, four-digit-year, or /archive/ path 404s. ~29 teams, ~350 players. When a season hasn't tipped off yet, games read 0-0 while age / contract / ability data is already populated.
02

Season codes → calendar years

URLs key on a season code, not the year. The mapping is almost 2000+N — with three pre-2000 exceptions and one hole.

CodeYearCodeYearNotes
961996002000Earliest three seasons are historical mirrors
971997NN = 2000+NN for 00–37
98— none —37203738 = 2038, the last completed season
991999current20392039 in progress — top-level, no /history/
1998 happened — only its archive is missing /history/98/ 404s, but player career-stats pages carry real 1998 season rows (331 players with games), and career totals on those pages include 1998. For career-continuity math count seasons by real-archive ordinal (96,97,99,00,01…), not by subtracting years.
03

The URL map

Every resource has a current-season form (top-level) and a historical form (/history/{code}/…). {rn} = roster number · {id} = player id.

ResourceCurrent (2038)Historical  {code}Key
Team roster/rosters/roster{rn}.htm/history/{code}/rosters/roster{rn}.htmseason + rn
Roster schedule/rosters/roster{rn}sched.htm/history/{code}/rosters/roster{rn}sched.htmper-day W/L
Player page/players/player{id}.htm/history/{code}/players/player{id}.htmseason + id
Player career stats/players/player{id}stats.htm/history/{code}/players/player{id}stats.htmseason + id
Season awards/regssnawards.htm/history/{code}/regssnawards.htmseason
Playoffs / champion/playoffs.htm/history/{code}/playoffs.htmseason + rn
All-Star box score/history/{code}/boxes/allstar.htmlby name
Day scoreboard/boxes/day{D}.htm/history/{code}/boxes/day{D}.htmlinks games
Per-game box score/boxes/{D}-{G}.html/history/{code}/boxes/{D}-{G}.htmlby name
Transactions/transactions.htm/history/{code}/transactions.htmseason + day
League schedule/leagueschedule.htm/history/{code}/leagueschedule.htmreg-season days
Divisional standings/divstand.htm(historical unverified)W/L/L10/GB
Playoff standings/playstand.htm(historical unverified)top-8 starred
Free agents/fa/fa-pos.htm(current only)Name+id, abilities, last team
Injuries (league-wide)/injuries.htm(historical unverified)Name/Team/Injury/Days
Injured Reserve/ir.htm(historical unverified)GM roster tool — see §5
Current-page year skew The top-level /regssnawards.htm and /playoffs.htm show the last completed season until the live one finishes. Always guard on the year the page prints, or you'll attribute last season's awards/champion to the current year. NDL: same patterns under /NDL/…, current season only.
04

Page anatomy

What each file actually contains, the columns that matter, and how to read them.

Team roster

/history/{code}/rosters/roster{rn}.htm
  • Team name = <title> minus " Roster".
  • 9 tables on the page; the one you want literally contains "Player Statistics".
  • Percents are proportion strings (.467), not %.
  • Also carries a Player Abilities table: In/Out/Hn/Df/Reb/Pot, letter grades A+…F.
  • Player links point to this season's player pages — recycled ids never collide here.
ID · Name · Pos · Games · MPG · PPG · RPG · APG · SPG · BPG · TPG · FG% · FT% · 3P%

Player career stats raw totals

/history/{code}/players/player{id}stats.htm
  • Season-by-season with raw makes/attempts — the only place FG/FT/3P counts live.
  • Per-season rows begin with a 4-digit year; a final Career: row holds official per-game avgs.
  • Points aren't published → compute 2·FG + 3P + FT (exact).
  • Reb/Ast/Stl/Blk/TO only as per-game → sum PG × Games (≈0.1% rounding), or count the box scores for exact totals.
Season · Team · Games · MPG · FG · FGA · FG% · FT · FTA · FT% · 3P · 3PA · 3P% · RPG · APG · SPG · BPG · TOPG

Player page

/history/{code}/players/player{id}.htm
  • <title> = "POS Name - Team" (e.g. "SF LeBron James - Pistons").
  • <textarea name="Awards">: every honor as "YYYY - Award" lines (incl. "All-Star Game Participant"; exclude "Rookie Game").
  • Achievements box: Double Doubles, Triple Doubles, Championships, Player of the Game.
  • Embeds the player{id}stats.htm iframe.

Per-game box scores exact counts

/history/{code}/boxes/{D}-{G}.html
  • Two team tables: Name · POS · MIN · FG · FGA · 3P · 3PA · FT · FTA · REB · A · PF · ST · TO · BL · PTS.
  • MIN and PF live only here — published nowhere else on the site.
  • Names unlinked → join by (season, name); only 5 ambiguous pairs across all seasons.
  • Regular-season day list = the boxes/day{D}.htm links on leagueschedule.htm; playoff boxes share the dir but are off-schedule.
  • gaps Same coverage as All-Star: 1999 + 2001–2038 + current. 14 box files missing upstream (9 days in 1999/01/02/04/24).
  • Summing boxes = exact career Reb/Ast/Stl/Blk/TO — validated to the unit vs the official records (Jrue Holiday 3,425 steals; Luka 15,587 assists through 2037).

Season awards

/history/{code}/regssnawards.htm
  • One consolidated page/season, ~39 slots.
  • MVP · DPOY · ROY · 6th Man · All-League 1st/2nd/3rd · All-Defensive 1st/2nd · All-Rookie 1st/2nd.
  • Names are linked with ids → join cleanly by (season, id).
  • Page prints its year ("1999 Regular Season Awards") — trust that over the URL.

Playoffs / champion

/history/{code}/playoffs.htm
  • The champion's roster link sits immediately after the word "Champion".
  • Join by (season, roster#) to get the winning franchise.
  • 42 champions on record (2039 still in progress).

All-Star box score

/history/{code}/boxes/allstar.html
  • Player names are unlinked → count by name, not id.
  • Archived for 1999 + 2001–2038 only.
  • gap 1996, 1997, 2000, 2005 boxes are missing — those games happened (see player award boxes) but aren't archived.

Transactions

/history/{code}/transactions.htm
  • Flat 4-col table: Season · Day · Team · Action; rows alternate bgcolor.
  • Each trade appears twice (once per team) → dedup by (day, teams, assets).
  • Format: "Trade {out} to the {counterparty} for {in}"; acting team = the Team column.
  • Assets split on ", " and " and "; picks from "one/N draft pick(s)".
  • In-season = day ≤ 122. Reg-season trades cluster days 1–100; offseason resumes ~day 170.
05

Conventions & the quirks that bite

The site is consistent, but a handful of behaviors will silently corrupt a naïve scrape. These are the ones learned the hard way.

Player identity is not the id

Ids are recycled across eras. Id 609 was Malik Sealy early, Brandon Roy later. An id is not a career key. To reconstruct a career, group a name's ids and split into careers on year-continuity: a run of ≥3 consecutive real seasons missing starts a new person. This keeps a mid-career id change as one player while separating two different people who share a name.

The big one — career-page resets A player's …stats.htm page normally holds their whole career, but the sim sometimes resets it to a fresh window mid-career — even under the same id (an un-retirement). The last-season snapshot then shows only the latest window, silently dropping earlier ones. LeBron James was the sole site-wide case: id 608 (2003–19) → id 3, whose page was itself reset from a 2020–25 window to a blank 2026–29 one. Reading only the final page undercounted him by 434 G / 10,056 pts. Fix: walk back through earlier-season snapshots of the same id and sum the non-overlapping windows.
What's exact vs approximate exact Games · Points (2·FG+3P+FT) · FG · FT · 3P · Double/Triple Doubles · Reb/Ast/Stl/Blk/TO when counted from box scores.   ≈ estimated Reb/Ast/Stl/Blk/TO for the no-box seasons (1996/97/2000/05, the unarchived 1998) and the 14 lost box files — derive those as PG × Games.

Other conventions worth trusting

Mid-season trades

  • A traded player's full-season stats are credited to their end-of-season team. The site never splits one season's line across teams.
  • But their season G can exceed 82 — games accumulate across both teams' schedules (Jrue Holiday: 92 G in 2016). A season is 82 team games: 29 teams → 1,189 league games.

Records page freezes the live season

  • Official career-record rows read value | holder | pos | year. For an active holder the value runs through the last completed season — a record can be de facto broken mid-season while the page still shows the old holder (LaMelo passed Jrue in steals mid-2038, on day 64).

Injuries ≠ Injured Reserve

  • Actual injuries live at /injuries.htm ("Injured Players": Name/Team/Injury/Duration in days), and per-team on each roster page's #injuries table.
  • /ir.htm is the GM-maintained Injured Reserve — a roster tool, not a medical report. Teams carry up to 15 players but only 12 can be playable; GMs stash up to 3 on IR to get down to 12. Players on IR may be healthy — duration 0 = healed but not yet activated.

Conferences & divisions

  • East = rn1–15, West = rn16–29. Divisions: Atlantic rn1–7, Central rn8–15, Midwest rn16–22, Pacific rn23–29.

Franchise = roster number

  • rn is stable through renames — rn3 is the Nets / "Brooklyn Ballers". Track franchise history by rn, not team name.

Ability grades

  • In / Out / Hn / Df / Reb / Pot on an F…A+ scale, consistent across every era. On the roster page's Player Abilities table.

Flaky reachability

  • The host occasionally refuses connections though the site is up. Retry transient HTTP (429/5xx); the site itself is fine.
06

Query playbook

Start here for a new question: which file answers it, and how to read it.

You want…Go toHow to read it
A player's line in one seasonroster{rn}.htm Player Statistics table row, or the stats-page row for that year. Per-game + shooting %.
A player's full career totalsplayer{id}stats.htm Sum the season rows; bundle ids by name-continuity; check for page resets (see §5).
Who won an award in year Y/history/{Y}/regssnawards.htm Linked names → ids. Verify the printed year matches Y.
A player's career award countplayer{id}.htm Award textarea, or sum per-season award pages across the name's career segment.
Champion of year Y/history/{Y}/playoffs.htm Roster link right after "Champion" → (season, rn) → franchise.
A team's roster in year Y/history/{Y}/rosters/roster{rn}.htm Player Statistics table. Find rn from any player link or the franchise's rn.
All-Star selectionsboxes/allstar.html Count unlinked names by year; mind the 1996/97/2000/2005 archive gap.
Trades in a season/history/{Y}/transactions.htm Dedup the double-listed rows; filter day ≤ 122 for in-season.
Player abilities / gradesroster{rn}.htm Player Abilities table (In/Out/Hn/Df/Reb/Pot), that season's snapshot.
Exact steals / rebounds / etc.boxes/{D}-{G}.html Sum box lines by name; day list from leagueschedule.htm; mind 4 gap years + 14 lost boxes.
Minutes or fouls totalsboxes/{D}-{G}.html MIN and PF exist only in the boxes.
Who's actually hurt right now/injuries.htm League-wide injury list with days remaining. (/ir.htm is the GM roster stash, not injuries.)