A browser-based prospect ranking engine for the Minor League Baseball Club (MLBC) simulation game. Upload your league export files and get instant, data-driven prospect rankings β no server, no Python, no installs required.
π Live app: https://ddecoen.github.io/mlbc_prospect_ranking
Each prospect row displays three stacked grade bars, styled to match the sim's own player card layout:
Hitters
| Bar | Color | What it measures |
|---|---|---|
| FLD | Purple | Fielding score β position-weighted range, arm, speed, hands |
| HIT | Green | Offensive score β OBP, XBH, K/BB, GB%, Pull |
| OVR | Gold | Overall (90% HIT + 10% FLD + all bonuses) |
Pitchers
| Bar | Color | What it measures |
|---|---|---|
| END | Red | Raw endurance value (shown as the actual END number, not a grade) |
| STF | Blue | Stuff score β pure W_OPS on the 20-80 scale |
| OVR | Gold | Overall (STUFF + END gate + all bonuses/penalties) |
All bars fill proportionally on the 20β80 grade scale β a grade of 70 fills ~83% of the bar, grade of 50 fills ~50%, grade of 30 fills ~17%. This makes it easy to scan down the OVR column and compare prospects at a glance without reading individual numbers.
The GRADES column shows the underlying component grades (OBP, XBH, K/BB for hitters; WOPS, KBB for pitchers). The BONUSES column shows pills for all active adjustments β positional premiums, power/leadoff bonuses, SP/RP status, elite closer/BP/K/BB bonuses, walk penalties, and hit tool penalties.
- Export two CSV files from your MLBC sim:
League_Roster_XXXX.csvβ full league player roster with all edits/gradesPro_Years_Report_XXXX.csvβ pro years report (filters to prospects with 0 pro years)
- Open the app and upload both files
- Rankings generate instantly in your browser β filter, sort, and export to CSV
The model is built around one core principle: grades are grades. A player's edits represent their true ability ceiling regardless of what level they play at. Level only tells you when you'll get the value, not how much value there is. No level-based adjustments are applied to scores.
The model separates hitters and pitchers completely, scoring each against the full non-ML prospect pool.
The offensive grade is built from five components on a 20β75 scale, calibrated to the full non-ML prospect population:
| Component | Weight | Stat | Logic |
|---|---|---|---|
| OBP Grade | 40% | (OBP_vL Γ 0.25) + (OBP_vR Γ 0.75) |
On-base is the most predictive offensive rate stat |
| XBH Grade | 38% | HRΓ4 + 3BΓ3 + 2BΓ2 |
Extra base value mirrors the sim's own fantasy formula |
| K/BB Grade | 15% | B_SO / B_BB |
Plate discipline β lower is better |
| GB% Grade | 4% | B_GB |
Small power-style signal β low GB% = fly ball tendency |
| Pull Grade | 3% | Pull% |
Small pull-power signal |
Why GB% and Pull are small weights: Early versions of the model weighted these at 12% and 8% respectively. This incorrectly penalized legitimate contact/gap hitters β a player who hits .845 OPS to all fields with a high GB% would score lower than a .803 OPS pull hitter. GB% and Pull are style signals, not outcome signals. OBP and XBH already capture the outcomes; GB% and Pull just add a small bonus for pull-power profiles without punishing other approaches.
Hit Tool Floor β Contact Credibility:
A poor hit tool creates two separate problems, both now modeled explicitly:
1. Contact-credibility discount on OBP grade. A player with B_H=155 cannot sustain a .390 OBP regardless of what his edit splits say β the splits assume a level of contact he can't produce. The OBP grade is discounted proportionally:
OBP_G = OBP_G_raw Γ min(1.0, B_H / 170)
So B_H=155 β OBP grade multiplied by 0.912 (9% discount). B_H=140 β 18% discount. B_H=170+ β no discount.
2. Flat hit tool penalty applied to the final overall score:
| B_H | Penalty | Notes |
|---|---|---|
| β₯ 170 | 0 | No penalty β acceptable contact |
| β₯ 160 | β1 | Slightly below average |
| β₯ 150 | β3 | Genuine contact risk |
| β₯ 140 | β5 | Significant red flag |
| < 140 | β8 | Cannot profile as a hitter |
The old model used a single -1 penalty for B_H=155, which was far too lenient. A walk-heavy, no-contact player (the "Barry Bonds eye with no contact ability" profile) would score artificially high because the OBP grade trusted edit splits that the hit tool makes impossible to sustain in the sim.
Defense is real but worth approximately 10% of a prospect's value. The sim's fantasy scoring is entirely offensive, but good defense helps pitchers and prevents runs.
Each position uses position-appropriate defensive weights with range z-scored within position group (so a 1B's range is compared to other 1Bs, not shortstops):
| Position | Primary Weight | Secondary |
|---|---|---|
| C | Arm 65% | Hands 25% |
| SS | Range 40% | Arm 25%, Run 20% |
| 2B | Range 40% | Arm 25% |
| 3B | Arm 45% | Range 30% |
| CF | Range 40% | Run 35% |
| RF | Arm 45% | Range 30% |
| LF | Range 40% | Run 30% |
| 1B | Hands 55% | Range 25% |
Throw hand constraint: Left-handed throwers cannot play meaningful infield positions other than 1B. LH throwers coded at 2B/3B/SS use OF range as their range component, which correctly penalizes the positional mismatch.
These bonuses recognize archetypes the sim rewards but raw grades don't fully capture:
| Bonus | Trigger | Points | Rationale |
|---|---|---|---|
| Positional Value | C, SS, CF, 2B, 3B, RF, LF, 1B | +3.0 to β0.5 | Scarce defensive positions are worth more at equivalent offensive output |
| True Power | OPS β₯ 1.050 | +3.0 | Generational bat β top 0.3% of prospect pool |
| OPS β₯ 1.000 | +1.5 | Elite power prospect | |
| OPS β₯ 0.950 | +0.5 | Plus power | |
| True Leadoff | OBP β₯ 0.390 + Run β₯ 5.5 | +2.0 | Both OBP and speed elite simultaneously |
| OBP β₯ 0.380 + Run β₯ 5.0 | +1.0 | Legitimate leadoff profile | |
| Bat Hand | Switch | +1.0 | Platoon advantage every at-bat |
| Left-handed | +0.5 | Slight platoon advantage vs. majority RHP |
Positional value premiums:
Premium positions (CF, SS, C) have athleticism-conditional bonuses β the premium only applies if the player can actually man the position at an above-average level.
For C and SS, the bonus is additionally scaled by the positional training rating (F_C and F_SS in the roster file, on a 0β1 scale). A catcher at F_C=0.51 gets 51% of the bonus β rewarding owners who properly train players at premium positions and correctly reflecting that an untrained catcher is a liability regardless of his arm. CF uses speed as the gate since speed is fixed in the sim and cannot be trained.
| Position | Condition | Raw Bonus | Scaling |
|---|---|---|---|
| C | Arm β₯ 8.0 | +3.0 | Γ F_C (0β1) β elite arm, top 25% of catchers |
| C | Arm β₯ 6.5 | +2.0 | Γ F_C (0β1) β good arm, real value |
| C | Arm β₯ 5.0 | +1.0 | Γ F_C (0β1) β fringe, modest premium |
| C | Arm < 5.0 | 0 | β bat must carry it; defense is a liability |
| SS | IF_Rng β₯ 5.0 | +2.0 | Γ F_SS (0β1) |
| SS | IF_Rng β₯ 4.0 | +1.0 | Γ F_SS (0β1) |
| SS | IF_Rng < 4.0 | +0.5 | Γ F_SS (0β1) |
| CF | Run β₯ 5.5 | +1.5 | No scaling (speed fixed) |
| CF | Run β₯ 4.5 | +0.75 | No scaling (speed fixed) |
| CF | Run < 4.5 | 0 | β |
| 2B / 3B | β | +0.5 | No scaling |
| RF / LF | β | 0 | β |
| 1B | β | β0.5 | β |
Example: Frank Prater has Arm=8.74 (raw bonus = +3.0, elite tier) but F_C=0.51 β actual bonus = 3.0 Γ 0.51 = +1.5. Once trained to F_C=1.0, he earns the full +3.0 β the true unicorn tier. Kevin Diaz (Arm=4.42, fully trained at F_C=1.0) gets +0 β a weak-armed catcher adds no positional premium regardless of training.
The pitcher model is built on one core insight: in a sim with fixed pitch probability distributions, W_OPS is a complete and sufficient quality metric.
The sim engine selects pitches randomly according to each pitcher's usage percentages (P1_Qual through P6_Qual). You cannot instruct your pitcher to throw his fastball more often β the probabilities are fixed. This means:
- The best pitch is already weighted into W_OPS by how often the sim calls it
- The worst pitch is already weighted into W_OPS by how often the sim calls it
- Pitch count doesn't matter β a 3-pitch pitcher who dominates with all three is equal to a 5-pitch pitcher with the same W_OPS
- Top-2 or bottom-1 metrics double-count what W_OPS already captures
Walks are already captured in per-pitch OBP against, which flows directly into W_OPS. K/BB only appears as a bonus for true outliers β it does not penalize anyone.
| Component | Weight | Stat | Logic |
|---|---|---|---|
| W_OPS | 100% | Usage-weighted OPS against across all pitches | Complete pitch quality signal β captures best, worst, mix, and command simultaneously |
Why K/BB is not in STUFF: Walks are already reflected in per-pitch OBP against β a pitcher who walks batters has a worse W_OPS as a direct result. Penalizing K/BB on top of W_OPS double-counts the same walks and systematically underrates pitchers who get outs without strikeouts: groundball artists, soft-tossers, and deception-based arms. In a sim where a strikeout and a groundout are both just outs, K/BB is not an independent quality signal on top of W_OPS. A pitcher like Charlie Blanco β three pitches all under .720 OPS, 65% GB rate β should not be ranked at 555th because his K:BB ratio is unflattering. His pitch outcomes are what matter.
How W_OPS is computed:
W_OPS uses the actual batter handedness distribution from the league, not a naive 50/50 split:
- LHP faces 76.4% RHH (R batters + switch hitters batting right vs LHP)
- RHP faces 64.7% RHH
For each pitch: OPS_weighted = OPS_vL Γ handedness_weight_L + OPS_vR Γ handedness_weight_R
Then: W_OPS = Ξ£(pitch_usage Γ OPS_weighted) across all pitches
This gives the true expected OPS on any randomly selected pitch, accounting for the actual distribution of batter types the pitcher will face.
Why not GB%? Ground ball rate is already implicit in W_OPS β a ground ball specialist allows fewer hits and fewer home runs, which shows up directly in his pitch OPS splits. Adding GB% as a separate component double-counts the same information while unfairly disadvantaging strikeout pitchers who achieve the same W_OPS through a different approach.
Why not K rate separately? Strikeouts are the best possible outcome (no baserunner, no defense required), but their value is already reflected in the per-pitch OPS against. A pitcher who strikes out 200 batters per 600 has a lower OPS against than one who strikes out 80, all else equal.
W_OPS grade scale is percentile-anchored to the actual non-ML prospect pitcher pool β not arbitrary absolute thresholds. This means grade 65 genuinely means top 10%, grade 70 means top 5%, and so on. Early versions used fixed OPS thresholds (e.g. grade 60 = W_OPS < 0.675) which compressed the entire top 5-15% of pitchers into two adjacent grades, causing quality arms to appear "below average" on the scale. The current bins:
| Grade | W_OPS threshold | Pool percentile |
|---|---|---|
| 80 | < 0.638 | Top 1% |
| 75 | < 0.659 | Top 3% |
| 70 | < 0.678 | Top 5% |
| 65 | < 0.703 | Top 10% |
| 60 | < 0.719 | Top 15% |
| 55 | < 0.736 | Top 25% |
| 50 | < 0.764 | Top 40% |
| 45 | < 0.811 | Top 60% |
| 40 | < 0.855 | Top 75% |
| 35 | < 0.908 | Top 90% |
| 30 | β₯ 0.908 | Bottom 10% |
Walk Penalty (context-aware):
Extreme walk rates hurt real roster value, but the penalty is discounted when total baserunners (H + BB) are still under control. A pitcher who walks 60 batters but only allows 120 hits (H+BB=180) is a very different problem from one who walks 60 and allows 175 hits (H+BB=235).
Base penalty by walk count:
| P_BB | Base Penalty |
|---|---|
| β₯ 55 | β1.0 |
| β₯ 60 | β1.5 |
| β₯ 65 | β1.75 |
| β₯ 70 | β2.0 |
| > 75 | β3.0 |
Context multiplier applied to the base penalty:
| H + BB total | Multiplier | Rationale |
|---|---|---|
| < 170 | Γ 0.25 | Walks acceptable β strong hit suppression compensates |
| 170β200 | Γ 0.50 | Manageable β worth monitoring |
| > 200 | Γ 1.0 | Full penalty β walks compounding a hit problem |
Example: P_BB=60, P_H=120 β H+BB=180 β penalty = β1.5 Γ 0.50 = β0.75. Same walk count with P_H=175 β H+BB=235 β full β1.5.
STUFF Multiplier (SP only):
A starter's STUFF grade is multiplied by 1.07 before any bonuses are applied (capped at 80). This reflects a fundamental sim reality: a starting pitcher affects more plate appearances per game than any position player. A hitter bats 4-5 times per game; a starter faces 27+ batters every 5 days. The 7% lift brings pitcher grades onto a comparable value scale with hitter grades before bonus stacking begins. Relievers do not receive the multiplier.
SP Quality Bonus:
Elite starters receive an additional bonus based on their scaled STUFF grade (post-multiplier):
| Scaled STUFF | Bonus | Profile |
|---|---|---|
| β₯ 75 | +3.0 | True ace |
| β₯ 70 | +2.0 | Solid #2 starter |
| β₯ 65 | +1.5 | Quality starter |
| β₯ 60 | +1.0 | Good starter |
| < 60 | 0 | No bonus |
Relievers never receive the SP quality bonus regardless of grades.
Endurance Bonus:
A workhorse starter who can go deep into games has roster value beyond pitch quality alone. Requires a quality gate (scaled STUFF β₯ 55) so a pitcher with poor edits doesnβt benefit just from eating innings badly:
| Condition | Bonus |
|---|---|
| END β₯ 8.0 + STUFF β₯ 55 | +2.0 |
| END β₯ 7.5 + STUFF β₯ 55 | +1.0 |
GB% Bonus (SP only):
Groundball pitchers are systematically undervalued by W_OPS alone. W_OPS captures OBP and SLG against but not the type of contact β a pitcher allowing 65% grounders prevents the extra-base hits and home runs that a fly-ball pitcher with the same W_OPS would give up. Requires a quality gate (STUFF β₯ 55) so a poor pitcher doesn't benefit just from weak contact:
| Condition | Bonus |
|---|---|
| GB% > 60% + STUFF β₯ 55 | +1.5 |
| GB% > 55% + STUFF β₯ 55 | +1.0 |
Only ~10-15 SP prospects qualify at the top tier, keeping it a meaningful differentiator rather than a broad inflation. Directly addresses the concern from experienced owners that control/groundball arms were being undervalued relative to strikeout pitchers with similar W_OPS.
Why these adjustments exist: Analysis showed pitchers represented only 14% of the top 50 despite being 43% of the prospect pool. Hitters stack up to +10 points in bonuses (positional premium + power + leadoff + bat hand) while pitchers had no equivalent. The 1.07 multiplier + bonuses bring pitchers to ~28% of the top 50 and ~35% of the top 100. The multiplier of 1.07 was chosen specifically to avoid overcorrection β higher values pushed average pitchers ahead of genuinely elite hitters.
- END β₯ 5.0 β Starter-eligible, no adjustment
- END < 5.0 β Reliever penalty (β3 points)
The penalty was reduced from β5 to β3 because some high-quality relievers have genuine roster value as swingmen or high-leverage arms. A β5 gate was washing out pitchers who belong in the top 200 regardless of role.
Elite Closer Bonus (+2.0):
A reliever with true ace-level pitch quality AND elite command is a genuine asset regardless of endurance. If a pitcher meets all three conditions:
- END < 5.0 (reliever role)
- W_OPS < 0.660 (top ~2.5% of the prospect pitcher pool)
- K/BB > 3.0 (elite command)
β¦he receives a +2.0 bonus. This partially offsets the β3 reliever penalty, netting β1 overall β correctly placing an elite closer just slightly below an equivalent starter.
Elite BP Arm Bonus (+2.0):
A swingman/setup arm in the END 4.0β4.9 tier with quality stuff and decent command also receives a +2.0 bonus:
- END 4.0β4.9 (swingman tier β not a true closer, not a starter)
- W_OPS β€ 0.680 (top ~5% of the prospect pitcher pool)
- K/BB > 2.5 (sufficient command)
Elite K/BB Bonus (+2.0):
Any pitcher β starter or reliever β with K/BB > 4.0 receives a +2.0 bonus. This is the top ~3% of the prospect pool and represents truly elite command that is meaningful on top of W_OPS (since K/BB is not otherwise penalized in STUFF).
All grades use the standard scouting 20β80 scale:
| Grade | Meaning | Pool percentile (approx) |
|---|---|---|
| 80 | Elite β top 1% of prospect pool | 99th+ |
| 75 | Plus-plus β top 2β3% | 97thβ99th |
| 70 | Plus β top 5% | 95thβ97th |
| 65 | Above average | 85thβ95th |
| 60 | Solid average+ | 75thβ85th |
| 55 | Average | 60thβ75th |
| 50 | Below average | 40thβ60th |
| 45 | Fringe | 25thβ40th |
| 40 | Poor | 10thβ25th |
| 35 | Well below average | 3rdβ10th |
| 20β30 | Bottom of pool | Bottom 3% |
Why the full 80 is available: In traditional prospect evaluation, grades are capped at 75 for prospects to leave headroom for development β a player rated 75 today might grow into an 80. In a sim, edits are fixed. A player with a .420 OBP edit will always have a .420 OBP edit. There is no development ceiling to protect, so a player whose grades genuinely put him in the top 1% of the prospect pool receives the 80 he deserves.
Bins are calibrated to the full non-ML prospect population so grades are consistent year over year regardless of which season's data is uploaded.
No level adjustment: The MLBC edits represent a player's true ability grades β they do not change as a player moves from A-ball to AAA. A 19-year-old in A-ball with elite grades should not be ranked below a 24-year-old in AAA with average grades just because he hasn't been promoted yet. Level tells you when you get the value. The ranking tells you how much value there is.
90/10 bat/glove for hitters: Analysis of the sim's fantasy scoring formula (1B=1, 2B=2, 3B=3, HR=4, BB=1, SO=β1) shows that offensive production drives virtually all measurable value. The run value difference between elite and poor defense is approximately 3β4 runs per season, while a single extra OPS point represents ~0.4 runs per 600 AB. The bat-to-glove run value ratio is approximately 10:1.
GB% and Pull as small signals, not large weights: GB% and Pull were originally weighted at 12% and 8% of HIT respectively. This created a systematic bias against contact/gap hitters β a player hitting .845 OPS to all fields would score lower than a .803 pull hitter because his high GB% and low Pull% dragged down his HIT score. GB% and Pull are style signals, not outcome signals. OBP and XBH already capture the outcomes. Reducing these to 4% and 3% means they add a small bonus for pull-power profiles without penalizing other legitimate hitting approaches.
Conditional positional premiums: The positional bonus should only apply when the player can actually play the position at a premium level. A CF with below-average speed (Run < 4.5) is really a corner outfielder playing center β giving him the same +1.5 bonus as a true center fielder with elite speed would systematically overrate him. The same logic applies to SS (gated on range) and C (gated on arm strength). Fixed bonuses based purely on the roster position label, regardless of whether the player has the tools to play it, produce rankings that no experienced scout would recognize.
Positional premiums instead of defensive scoring inflation: Rather than letting fielding grades inflate overall scores for corner players (a known bug in earlier versions of this model), positional scarcity is handled as a clean additive bonus. This correctly ranks a .850 OPS shortstop above a .850 OPS first baseman without letting IF_Rng artificially boost a first baseman's score.
W_OPS as the complete pitcher signal: Early versions of the model added components like Top-2 pitch quality, worst pitch OPS, and strikeout rate on top of W_OPS. All of these are wrong for the same reason: the sim selects pitches from a fixed probability distribution. You cannot instruct your pitcher to throw his fastball more. Because the usage percentages are fixed sim probabilities, W_OPS already captures every aspect of pitch quality β the best pitch is weighted by how often the sim calls it, the worst pitch is weighted by how often the sim calls it, and everything in between. Adding any pitch-specific component on top of W_OPS is double-counting. K/BB is only rewarded as a bonus for true outliers (K/BB > 4.0), never penalized.
Percentile-anchored W_OPS bins: Early bin calibration used arbitrary absolute OPS thresholds that compressed the entire top 5β15% of pitchers into two adjacent grade buckets. A pitcher in the top 5% of the pool was getting a grade of 55 β "below average" on the 20-80 scale. The current bins anchor each grade to an actual percentile of the non-ML prospect pitcher pool so that grade 65 genuinely means top 10%, grade 70 means top 5%, and so on. This fixed systematic underrating of quality pen arms whose W_OPS fell just outside the elite tier.
No GB% for pitchers: Ground ball rate is already embedded in W_OPS β a pitcher who generates grounders allows fewer hits and fewer home runs, which shows directly in his pitch OPS against. Adding GB% as a separate term double-counts it while penalizing strikeout pitchers who achieve the same W_OPS through a different approach. Both are valid pitcher archetypes; W_OPS correctly treats them equivalently at the same run prevention level.
The app expects the standard MLBC CSV export format. Key columns used:
Hitters: Bat, Throw, Run, Arm, IF_Rng, OF_Rng, Fld, B_H, B_B2, B_B3, B_HR, B_BB, B_SO, vL_OBP, vL_SLG, vR_OBP, vR_SLG, Pull, B_GB
Pitchers: Throw, END, P_SO, P_BB, P1βP6, P1_QualβP6_Qual, P1_vL_OBPβP6_vR_SLG
Both: Last, First, Age, Pos, Team, Level
Pro Years Report: Firstname (or First), Lastname (or Last), Pro Years
MIT License β see LICENSE for details. Free to use, modify, and share.
Pull requests welcome. Key areas for improvement:
- Catcher framing bonus (arm data exists but framing grade does not)
- Multi-position eligibility display
- Career trajectory tracking across seasons
- Draft board mode (A-ball only filter with pick slot context)