Pennant Games Documentation
Pennant Games is a basketball simulation game. Build a team from legends, current NBA players, and legacy on-chain players. Play exhibition games, compete in leagues with friends, and track every stat.
Getting Started
Pennant Games is currently in early access. Create an account with your email and sign in. If registration is closed, you can request an invite from the signup page. From the dashboard you can:
- Play exhibition games — pick any players, simulate a game or series instantly
- Create or join a league — compete with other users through a full season with draft, trades, playoffs, and awards
- Connect your wallet — claim legacy players from the original on-chain project
- Browse players — search and filter legends, current NBA stars, college prospects, and legacy players
- Enable two-factor authentication — add TOTP-based MFA from your dashboard security settings
Exhibition Games
Exhibitions let you simulate games without being in a league. This is the fastest way to see the engine in action. Go to Play → Exhibition in the nav bar.
Game Modes
- 5v5 — full team basketball with substitutions, coaching, and regulation quarters. Standard NBA-style game.
- 3v3 — half-court three-on-three. Played to a target score (11 or 21), 1s and 2s scoring, no free throws. Higher turnover rate, more interior play.
- 1v1 — half-court one-on-one. Pure ISO scoring — no assists, no chemistry. Highest turnover rate. Tests individual skill head-to-head.
3v3 and 1v1 use modified tuning: no home court advantage, no free throws (fouls change possession), faster possessions, and win-by-2 rule.
Building a Roster
For 5v5, each side needs at least 5 players (max 15). For 3v3, pick 3 players per side. For 1v1, pick 1 player per side. Use the search bar and filters to find players:
- Search by name — type any part of a player's name
- Filter by type — Legends, NBA 25-26, Legacy, Rookies
- Filter by position — PG, SG, SF, PF, C
- Filter by star rating — exact star level (5, 4, 3, 2, 1)
- Filter by NBA team — select a team abbreviation to see all players from that franchise
- Random fill — auto-populates a roster from filtered results
Selecting Starters
For 5v5, once you have 5 or more players, checkboxes appear next to each player name. Select exactly 5 to set your starting lineup. If you don't pick starters, the engine auto-selects the best player at each position by star rating.
Series Play
Choose between a single game or a best-of-3, 5, or 7 series. In a series:
- Home court alternates using the 2-2-1-1-1 format (games 1-2 home, 3-4 away, 5 home, 6 away, 7 home)
- Each game gets its own box score, shot chart, play-by-play, and AI recap
- A game selector lets you switch between games in the series
- After the series, a Three Stars section shows the top 3 performers by total Game Score
- A Series Averages table shows per-game stats (including MPG) for every player across the series
Saving Teams
Save your favorite lineups as named exhibition teams. Saved teams appear on your dashboard with links to team detail pages. You can also delete saved teams you no longer need.
Leagues
Leagues are where you compete with other users over a full season — draft, regular season, trades, playoffs, and awards.
Creating a League
Go to Leagues → Create League and configure:
- Max teams — how many users can join (2-30)
- Games per team — regular season length (2-82)
- Roster size — min and max players per team (8-15)
- Playoff format — number of qualifying teams, series length (single game, Bo3, Bo5, Bo7)
- Draft format — snake, linear, or auction
- Draft rounds — how many rounds
- Draft timer — seconds per pick before auto-draft kicks in (0 = no timer)
- Draft player pool — which player types are available: Legends, NBA 2025-26, Rookies/College
- Player type limits — max number of each player type a team can draft (e.g., max 3 legends)
- Legacy players — allow legacy (NFT) players on rosters, and set how many can be used per game
- Salary cap — optional cap with configurable amount
- Trade deadline — block trades after a configurable point in the season
Joining a League
Users can request to join a league, and the commissioner approves or declines requests. The commissioner can also invite users directly. When joining, you create a new team for that league — pick from 50 prefilled team names or enter your own. Each league has separate teams with separate rosters; the same player can be on different teams in different leagues.
League-Scoped Rosters
Rosters are league-specific. When a player is drafted or signed in League A, they're only on that team in League A. The same player can be drafted by a different team in League B. Trades and free agent signings only affect the league they happen in.
The one exception is legacy players — these are globally owned by wallet holders and can be brought into any league (subject to league rules). Legacy players are NOT available in the draft; they come from wallet claims only.
Season Flow
A full season follows this lifecycle:
- Setup — commissioner creates the league, users join and create teams
- Draft — snake/linear/auction format, ordered by inverse standings. Auto-GM can draft for teams. Player type limits enforced.
- Regular season — round-robin schedule generated automatically. Commissioner can simulate by day, week, month, all season, or up to a specific date.
- Standings — wins, losses, win %, games back, streak, last 10, point differential
- Trades — propose trades within the league. Both sides must agree. Commissioner can veto. Trade deadline enforced.
- Free agency — sign or release players. Free agents are league-specific — a player on a team in League A is still available in League B.
- Playoffs — top N teams seeded by record. Bracket with configurable series length.
- Awards — MVP, DPOY, ROY, stat leaders
- Advance — season ends, new draft order set, next season begins
Simulation Controls
The commissioner controls when games are simulated:
- One day — simulate all games scheduled for the next game day
- One week — simulate the next 7 game days
- One month — simulate the next 30 game days
- Full season — simulate all remaining scheduled games
- To a date — simulate all games up to a specific date
Trades
- Propose trades involving players and/or draft picks from both teams
- Player ownership is validated against the league roster (not global)
- Resulting roster sizes must stay within league limits
- The commissioner can veto any trade
- Trade deadline blocks new proposals after the configured game count
Free Agency
Free agents are league-specific — players not on any team in that league. A player rostered in League A is still a free agent in League B. Legacy players that have not been claimed by any user are excluded from the pool.
Player System
Every player in Pennant Games has a detailed attribute profile that drives how they perform in the simulation engine. There are no random dice rolls — every outcome is determined by attributes, coaching settings, fatigue, matchups, and context.
Player Types
| Type | Description | Count |
|---|---|---|
| Legends | All-time greats from every era (1950s-2010s). Attributes derived from career stats with era adjustments for pace and scoring context. | ~150 |
| NBA 2025-26 | Current NBA players from the active season. Attributes derived from per-game stats, shooting splits, and advanced metrics. | ~550 |
| College / Rookies | Top college prospects entering the draft. Stats are pace-adjusted (48/40 scaling), with age bonuses for younger players and discounts for older upperclassmen. Team context adjustments reduce stats for players on stacked rosters (e.g., Duke, Kentucky). | ~70 |
| Legacy | 3,662 on-chain players from the original project. Claimable by wallet holders. Hidden from other users until claimed. | 3,662 |
Positions
Every player has a primary position and an optional secondary position: PG (Point Guard), SG (Shooting Guard), SF (Small Forward), PF (Power Forward), C (Center).
The engine does not enforce traditional 5-position lineups. You can run 5 point guards or no center if you want — but there are consequences. Teams with all 5 positions represented get a chemistry bonus. Substitutions prefer same-position replacements. And positions affect stamina drain rates (guards tire faster than bigs).
The 15 Skill Attributes
Each attribute is rated on a 30-100 scale. Here's what each one controls in the simulation:
Shooting (4 attributes)
| Attribute | Abbr | What It Does |
|---|---|---|
| Deep Range | DEEP | Three-point shooting accuracy. Directly drives 3PT make probability. |
| Pull-Up Game | PULL | Mid-range shooting accuracy. Drives mid-range make probability and shot selection affinity. |
| Inside Game | INSD | Near-basket scoring — layups, dunks, post moves. Drives interior make probability. |
| Charity Stripe | CFTS | Free throw accuracy. Drives FT make probability. |
Rebounding (2 attributes)
| Attribute | Abbr | What It Does |
|---|---|---|
| Crash the Glass | CRSH | Offensive rebounding. Affects team OREB rate and individual rebound probability. High-value skill — an offensive rebound creates a new possession. |
| Board Control | CTRL | Defensive rebounding. Affects team DREB rate and individual rebound assignment. |
Playmaking (1 attribute)
| Attribute | Abbr | What It Does |
|---|---|---|
| Court Vision | VIS | Passing ability and assist generation. Higher vision means more assists on made shots and better ball movement. |
Defense (2 attributes)
| Attribute | Abbr | What It Does |
|---|---|---|
| Rim Guard | RIMG | Shot blocking and interior defense. Reduces opponent interior FG% and drives block probability. |
| Lockdown | LOCK | Perimeter defense, lateral quickness, on-ball defense. Reduces opponent perimeter FG% and drives steal probability. The engine uses individual matchup defense — your defender is matched by position, and their lockdown rating directly affects the shooter they're guarding. |
Physical & Intangibles (6 attributes)
| Attribute | Abbr | What It Does |
|---|---|---|
| Strength | STR | Physical strength and size. Affects rebounding contests and post play. |
| Motor | MOT | Effort and hustle. Affects rebounding, loose balls, shot contests, and stamina usage. |
| Awareness | AWR | Decision-making and positioning. Reduces turnovers and affects defensive rotations. |
| Durability | DUR | Resistance to fatigue and injury. Higher durability means slower stamina drain. |
| Presence | PRES | Clutch performance and leadership. Boosts shooting in close games and late-game situations. |
| Adaptability | ADP | Versatility across roles. Contributes to overall rating, especially for forwards who need to play multiple positions. |
Ratings, Stars & OVR
Overall Rating (OVR)
Each player's OVR is computed as a position-weighted average of their 15 attributes. Different positions value different attributes:
- Point Guards — Court Vision, Awareness, and Presence matter most. Deep Range and Lockdown are important but not dominant.
- Shooting Guards — Pull-Up Game, Lockdown, and Presence are key. Scoring efficiency and perimeter defense define the position.
- Small Forwards — The most balanced position. Presence and Adaptability are weighted highest, rewarding versatile two-way players.
- Power Forwards — Crash the Glass, Inside Game, and Board Control lead. Scoring and rebounding dominate.
- Centers — Crash the Glass, Board Control, Rim Guard, and Strength are all weighted at 1.0. Interior dominance is everything.
Irrelevant attributes are zeroed out — a point guard isn't penalized for low Rim Guard, and a center isn't penalized for low Deep Range.
Star Rating
| Stars | OVR Range | Who's Here |
|---|---|---|
| 5 ★ | 93+ | All-time greats, current superstars (Jordan, LeBron, Jokic, Luka) |
| 4 ★ | 80-92 | All-Stars, franchise players (Tatum, AD, Dirk, Wade) |
| 3 ★ | 67-79 | Quality starters, solid role players, top college prospects |
| 2 ★ | 55-66 | Rotation players, bench contributors, average college players |
| 1 ★ | Below 55 | End-of-bench, deep reserves |
How Ratings Are Derived
Player attributes are computed from real basketball statistics, not manually assigned. The system converts per-game stats (PPG, RPG, APG, shooting splits, etc.) into the 15-attribute system using calibrated formulas:
- Shooting attributes use a volume × efficiency composite (makes per game × shooting percentage)
- Legend ratings include an era adjustment — players from the 1990s-2000s slow-pace era get their volume stats scaled up to modern equivalent
- College ratings include pace adjustment (48/40 scaling), age bonuses for younger prospects, and team context discounts for players on stacked rosters
- Elite scaling pushes top-tier attributes closer to 100, simulating that the best players don't just have good stats — they dominate
Hidden Attributes
In addition to the 15 visible attributes, each player has 5 hidden attributes (0-1 scale) that affect in-game behavior:
- Consistency — game-to-game variance. High consistency = reliable performance. Derived from Awareness.
- Hot Hand Tendency — likelihood of going on streaks (consecutive makes boost shooting). Derived from Deep Range.
- Foul Tendency — how often the player commits fouls. Derived from Strength.
- Injury Proneness — base injury risk per possession. Inverse of Durability.
- Usage Tendency — how much the player demands the ball. Derived from scoring attributes. High-usage players take more shots.
Data Sources
- Legends — career per-game averages from the NBA stats API. Era-adjusted for pace differences. ~150 players from 1950s-2010s.
- NBA 2025-26 — current season per-game stats from the NBA stats API. All players with 1+ games played. Updated seasonally.
- College — prospect stats from scouting databases. Pace-adjusted (48/40 min), age-discounted, team-context-adjusted for stacked rosters.
- Legacy — 3,662 on-chain players from the original Swoops project. Revealed + estimated attributes. Claimable by wallet holders.
- Rookies — procedurally generated using position archetypes with Gaussian variance. 10% five-star, 15% four-star, 30% three-star, 30% two-star, 15% one-star.
Simulation Engine
The engine is a pure-logic, possession-by-possession Monte Carlo simulator. It takes two Team objects (rosters, coaching settings, starting lineups) and produces a complete game result with every play recorded.
Possession Flow
Every possession follows this sequence:
- Non-shot foul check — defensive fouls can occur before a shot attempt. If the team is in the bonus, free throws are awarded.
- Turnover check — probability based on offensive awareness vs defensive lockdown, coaching intensity, shot clock pressure, and fatigue. If a steal, the matchup defender (the player guarding the ball handler) is 3x more likely to get credit.
- Shot selection — the shooter is chosen by usage tendency, modified by coaching ball movement. Shot type (3PT, MID, INT) is selected based on coaching tendencies and the shooter's attribute affinities.
- Defensive contest — the engine assigns individual defensive matchups by position. Perimeter shots are contested 70% by the matchup defender + 30% team help defense. Interior shots blend the matchup defender with the best rim protector.
- Block check — interior and mid-range shots can be blocked. The matchup defender and best rim protector compete for the block, weighted by Rim Guard + Motor.
- Make/miss resolution — probability determined by shooter attributes, stamina, hot/cold hand, consistency variance, defensive contest, clutch modifier, momentum, chemistry, and home court advantage.
- Rebound — on misses, offensive vs defensive rebound probability is computed from Crash the Glass vs Board Control, with height bonuses. Individual rebounder selected by weighted random.
- Free throws — awarded on shooting fouls (2 or 3 depending on shot type) or bonus situations.
- Substitution check — after each possession, the engine checks for fouls outs, injuries, fatigue, foul trouble, minutes management, and garbage time. Subs prefer same-position replacements.
Fatigue System
Every player has a stamina meter (0-1) that drains each possession based on their position (PGs drain fastest at 1.1x, Centers slowest at 0.9x) and durability attribute. As stamina drops:
- Shooting accuracy decreases
- Turnover probability increases
- Players are subbed out when stamina falls below 35%
- Bench players recover stamina while sitting
Chemistry
Team chemistry is computed from three factors:
- Presence score (40%) — average Presence attribute of on-court players
- Adaptability score (40%) — average Adaptability, representing how well players fit together
- Position balance (20%) — bonus for having all 5 positions represented. Running 5 PGs gives only 20% of this bonus.
Chemistry affects assist rate, turnover rate, and shooting accuracy (approximately ±1-2% FG).
Momentum
Teams on a scoring run get a small shooting boost (up to ~2% per consecutive scored possession). This creates realistic runs and momentum swings.
Clutch Mode
When the game is within 5 points in the final 5 minutes, clutch mode activates. Players with high Presence get a shooting boost; players with low Presence get penalized. This simulates the real-world phenomenon of stars rising in big moments.
Hot/Cold Hand
Players can get hot (consecutive makes) or cold (consecutive misses). The Hot Hand tendency hidden attribute controls how likely streaks are to develop. A hot shooter gets up to a ~3% FG boost; a cold shooter gets a similar penalty.
Coaching Settings
Each team has configurable coaching settings that affect gameplay:
| Category | Setting | Effect |
|---|---|---|
| Offense | Pace (1-10) | Game speed — higher pace = more possessions, faster clock consumption |
| Offense | 3PT Tendency | How often the team shoots threes vs mid-range vs interior |
| Offense | Ball Movement | Higher = more uniform shot distribution; lower = star-heavy usage |
| Offense | Fast Break | Likelihood of transition plays after turnovers/rebounds |
| Defense | Intensity (1-10) | Aggressive defense creates more steals but also more fouls |
| Defense | Help Defense | How much team help compensates for weak individual matchups |
| Rotation | Depth (8-12) | How many players get regular minutes |
| Rotation | Starter Minutes | Target minutes for starters (28-40) |
| Rotation | Garbage Time | Point margin threshold to pull starters in blowouts |
Defensive Matchups
The engine uses individual matchup defense rather than generic team defense. Each offensive player is matched to the defender closest to their position:
- A PG is primarily guarded by the opposing PG (or SG if the PG is a weak defender)
- A C is primarily guarded by the opposing C
- Perimeter shots (3PT/MID) are contested 70% by the individual matchup + 30% by team help defense
- Interior shots are 50/50 between the matchup defender and the best rim protector
- The help defense coaching setting determines how much team defense compensates for a weak individual matchup
This means a team with one elite perimeter defender (like a Kawhi Leonard) won't lock down all five opponents — only the player he's matched against.
Game Results & Visualization
Every simulated game produces comprehensive results:
AI Game Recap
Each game generates a 4-5 paragraph sportswriter-style narrative recap covering the game flow, key performers, shooting comparisons, and the final outcome. Series games get individual recaps for each game.
Win Probability Chart
A real-time win probability curve tracks each team's chance of winning throughout the game. The model uses a statistical approach based on the current margin and time remaining — the standard deviation of possible outcomes shrinks as the game progresses, so a 10-point lead means more in Q4 than Q1.
Game Flow Chart
A step-function line chart shows both teams' cumulative scores over time. Hover over any point to see the exact score, play description, and game clock. Quarter boundaries are marked with vertical lines.
Shot Chart
An interactive half-court visualization of every shot attempt:
- Green circles = made shots (dark green for 3PT, medium for MID, light for INT)
- Red × marks = missed shots (same shade system)
- Hover tooltip = shows shooter's last name and distance from basket
- Filter by quarter or by player to focus on specific situations
Box Score
Full per-player statistics including minutes, points, FG/3PT/FT splits, rebounds (offensive + defensive), assists, steals, blocks, turnovers, personal fouls, plus/minus (tracked per-possession), and Game Score (Hollinger formula). Starters are separated from bench players.
Team Comparison
Side-by-side team stats with shooting splits, rebounding, assists, steals, blocks, turnovers, and fouls. Includes the Four Factors of basketball analytics: eFG% (effective field goal percentage), TOV% (turnover rate), ORB% (offensive rebound rate), and FT Rate (free throw rate relative to field goal attempts).
Play-by-Play
Every event in the game is recorded with quarter, game clock, team, play type, and natural language description. Filter by quarter or player to review specific sequences.
Wallet & Legacy Players
Legacy players come from the original on-chain basketball project — 3,662 ERC-721 NFT players across 723 Ethereum wallets.
Claiming Your Players
- Go to your dashboard and find the Wallet section
- Connect your Ethereum wallet (MetaMask or any wallet extension)
- Review the verification prompt — confirms this is a free signature, not a transaction
- Sign the nonce-protected message — proves wallet ownership without spending gas
- Players are auto-claimed — any legacy players on that wallet are linked to your account
You can connect multiple wallets if your players are spread across them. The signing message includes a one-time nonce to prevent replay attacks.
Using Legacy Players
- Exhibitions — add to any exhibition lineup freely
- Leagues — bring onto your league team if the league allows legacy players. Each league sets how many legacy players can be used per game (e.g., max 3).
- Available everywhere — the same legacy player can be on different teams in different leagues simultaneously. They're your players globally.
- NOT in the draft — legacy players come from wallet claims only, not the draft pool
- Rename — assign a custom display name that appears everywhere the player is shown
Ownership Verification
Since legacy players are NFTs that can be traded on OpenSea and other marketplaces, Pennant Games verifies on-chain ownership before each game simulation. If an NFT has been transferred to a different wallet since claiming, the player is automatically unclaimed and removed from league rosters. The new wallet holder can then claim and use them.
Security
- Wallet addresses are never exposed in public API responses
- Signatures use a one-time nonce with 5-minute expiry to prevent replay
- The signed message explicitly states it does not approve transactions or transfers
- A wallet can only be linked to one account — prevents multi-account exploits
Legacy players are not visible to other users in player searches or free agency until claimed.
Contact
Pennant Games is under active development. For questions, feedback, or bug reports, email hello@pennantgames.com.
Disclaimer
Pennant Games is an independent basketball simulation game. It is not affiliated with, endorsed by, or connected to the NBA, NBPA, any professional basketball league, or any prior basketball game project. Historical player names and statistics are used under First Amendment protections as established in CBC Distribution v. Major League Baseball Advanced Media (2007).