We're two months into the development of Earth's only collegiate tennis sim and I decided to do something even more unhinged, I created the world's only high school dual tennis simulator on top of it. Why? Well, I'd already the demo spec for VarsityApex, my ATProto demo tool to show you can take messy content and organize.

The college sim was fun and felt mostly realistic, the juniors game was designed as a one-shot sim that layered onto the college game and focuses on recruiting which is how all college sims in any sport are built. When I had all of the VarsityApex data -- which created a fictional state to show how it works -- I wanted to visualize it and decided that since the tennis sim already existed, it would be a good place for the high school data.

Upon simming, it was clear the high school game needed work. So over the course of play testing when I had time, I improved the model, removed constraints and rebuilt the assumptions around what a tennis game needs to do. None of this would be that interesting even if you were some kind of tennis fan, but I think from a game development perspective, being able to create malleable structures around how players develop in games is something that's been debated for years.

A few months ago, I wrote about the baseball sim I built and it's development model specifically about interest-rate development and access lenses. I had already brought parts of that model into tennis, and revisiting it showed me how differently the two sides of the tennis sim had evolved.

This is the story of measuring what the model was doing, revising the assumptions underneath it, and rebuilding player development around the careers I wanted the simulation to produce.

Two development systems

I've been simming the same HS universe inside the tennis sim for over 30 seasons. I've made changes to the format over time, and player creation as time has gone one. One thing I'd noticed recently wa that seniors held 85.7% of the No. 1 singles seats, I knew the development model needed a different premise.

The college side runs the baseball model, including interest_ratetier_multfog, and the 75/20/5 development-tier split. Growth closes a fraction of the distance to a fixed potential every season:

frac = interest_rate × GROWTH_K (0.12) × tier_mult
current[a] += frac × (potential[a] − current[a])

The high school side developed separately.

JHSAA rosters are regenerated deterministically from (school, gender, entry year, seat). High school development reads the same fixed ceiling through a grade-dependent maturity number.

The two systems therefore arrived at similar career behavior through different mechanisms: gradual movement toward a value established at generation.

College movement was small

The ordinary college player, 75% of every class, closes about 0.6% to 6.0% of the remaining gap per year.

A median ordinary player with a 60 ceiling entering college at 51.9 finishes senior year around 52.7.

That is about +0.8 OVR across a four-year career.

College freshmen also arrive with roughly 83–90% of their ceiling already available, which leaves a relatively small amount of development for the college years.

High school produced a strong grade order

The high school model already had a per-player trajectory: an arrival band, a finish band, and a curve shape.

Across three archived seasons, the access distribution looked like this:

Grade | Mean access | p10 | p50 | p90

9 | 0.614 | 0.455 | 0.596 | 0.800

10 | 0.706 | 0.569 | 0.702 | 0.842

11 | 0.781 | 0.675 | 0.781 | 0.885

12 | 0.870 | 0.791 | 0.875 | 0.938

13.4% of freshmen reached the junior median. 1.3% reached the senior median.

The earlier lockstep system put the freshman-over-senior-median number at 0.0%. The trajectory model widened the overlap, while the overall grade ordering remained strong.

Measuring the baseline

I wrote a reproducible script to fold three seasons of research exports into a baseline. The measurements changed my understanding of the problem.

The amount of development was substantial

Tracking the same player across two seasons, freshmen gained:

  • +8.5 OVR for girls

  • +9.7 OVR for boys

The distribution ran from roughly +2 at p10 to +16 at p90.

The important issue was ordering.

Returning teammates swapped ladder order only about 7.7% of the time. Players improved by similar amounts on similar schedules, which preserved much of the original roster order.

Ceiling stayed almost entirely fixed

For the same player over two years, ceiling moved for about 1.0% of players, with a mean change of +0.02.

That made access the main source of developmental variation, and access remained closely associated with grade.

A quarter of the association stayed outside varsity

Among players observable across the full three-season window, 25.4% never reached a varsity lineup.

JV changed the meaning of that population. Players below the varsity line now had a competitive environment that could become part of development.

A large amount of freshman talent sat below the varsity line

Ranking each roster by ceiling instead of current ability raised freshman lineup presence from 31.9% to 54.8%.

That measurement showed how much generated talent remained unavailable through the maturity schedule.

One measurement also needed an era correction. The 2059 seniors had ceilings about five points higher than the freshmen because talent compression phased in beginning with entry year 2057. The older cohort came from the earlier generation model. Comparing ceilings by entry year gave the clean read across that boundary.

The Oregon reference point

I have six seasons of real OSAA results in a separate repository: 295,219 varsity appearances across 11,135 players.

That data gave me a useful reference for the age composition of real high school lineups.

The source grade field is mostly current status, and the graduatedDate field contains a bulk 2025 entry for many players. I therefore inferred grade from appearance history and used full four-season careers as the clean cohort.

Share of No. 1 singles:

| 9 | 10 | 11 | 12

Oregon boys | 5.3% | 19.7% | 32.3% | 42.7%

Oregon girls | 6.3% | 27.0% | 30.1% | 36.6%

My sim | 1.7% | 4.6% | 12.2% | 81.5%

Sophomores produced the largest gap. Real sophomores held 20–27% of No. 1 singles positions. The sim gave them about 3–5%.

A returning Oregon No. 1 kept the seat about 63% of the time. The sim sat around 85–91%.

I used Oregon as a reference for lineup shape. Jefferson has its own talent distribution, and the goal was a more fluid age structure inside that world.

Testing individualized access

My first redesign kept the fixed-ceiling architecture and widened the player-specific access schedules.

I built a harness that swapped the access model over the same rosters, ceilings, and grades. The control reproduced the shipped behavior closely enough to support comparisons.

The main constraint appeared in the finish range.

DEV_FINISH was (0.76, 0.94).

Arrival access varied widely. Finish access converged.

A player could arrive at 0.42 or 0.78 of potential and still finish inside a relatively narrow senior range.

That meant the senior ladder increasingly reflected ceiling order, and ceiling had already been assigned at generation.

Widening the finish range improved freshman representation and roster movement. A deliberately unconstrained experiment with freely redrawn annual access showed that fixed-ceiling access could generate much more movement if the system abandoned the development rules I wanted to preserve.

That experiment pointed toward a different model.

Refining the metric

The headline ladder-swap statistic also needed refinement.

It counted every returning teammate pair, including players separated by twenty OVR points who had little chance of crossing.

Restricting the measure to players close enough to change order produced much more movement in the existing model.

The strongest remaining signals were No. 1 retention and the grade distribution near the top of the lineup.

The career model

The new model treats a player as four things generated at entry:

PLAYER
├── STARTING ABILITY
├── CAREER PEAK
├── YEARLY DEVELOPMENT CAPACITY ×4
└── EXPOSURE

Starting ability and career peak are drawn separately.

They remain correlated, while each contributes different information.

That produces careers such as:

61 / 63    already near finished as a freshman
51 / 70    elite upside
38 / 64    a project
44 / 47    nearly finished at fourteen
31 / 55    ordinary player with room

A highly developed freshman can therefore enter high school close to the player's eventual level.

Yearly development capacity

Each player receives a hidden development capacity for each year of the career.

Conceptually:

+1, +11, +3, +2

or:

+0, +1, +1, +0

or:

+3, +4, +5, +4

or:

+1, +2, +3, +13

These values describe available development during each period.

Career shapes emerge from the draws:

  • ready

  • early

  • steady

  • late

  • spike

  • stagnant

  • high peak with limited realization

The database stores the underlying values. The career type emerges from them.

The largest development year can occur at any point in the four-year sequence.

Career peak as a projection

The first parameterization used career peak as a hard clamp.

That also generated the apparent senior taper. Capacity was drawn identically across all four years, while later gains increasingly ran into the career-peak boundary.

The relationship looked like this:

Overflow past peak | 9→10 | 10→11 | 11→12 | Y3 ÷ Y1

0.00 | 3.9 | 3.3 | 2.5 | 0.62

0.20 | — | — | — | ~0.73

1.00 | 4.5 | 4.6 | 4.5 | 1.00

The shipped overflow is 0.20.

About a third of players finish above their generated career peak. Peak therefore functions as an expected career level with some headroom, while still contributing to the gradual taper in later years.

Playing time as an odometer

Development now includes competitive exposure.

Appearances accumulate as varsity-equivalent units. A JV appearance is worth half a varsity appearance. The total saturates and maps to a realization factor from about 0.55 for a rostered player with zero appearances to 1.0 for a full varsity season.

That gives a continuous range:

  • little or no match exposure

  • partial JV

  • full JV

  • split JV and varsity

  • full varsity

A full JV season lands around 0.81 realization. An eight-JV / six-varsity split lands around 0.87.

Exposure multiplies each player's own development capacity.

A player with +1 available development realizes roughly +1 even with extensive match exposure. A player with +12 available development can realize much more during a full varsity season.

The odometer reads appearances. It leaves wins, records, opponent quality, team finish, and State qualification outside the development calculation.

Freeing the high school scale

Jefferson's rating scale had also been shaped around the eventual college handoff.

The high school system describes ability within Jefferson. The college system has its own rating distribution.

The handoff already contained the translation mechanism I needed.

The national college recruit class is generated independently on the college scale. Jefferson graduates are rank-matched into the Jefferson positions on that board, and their high school ability stays on the high school record.

That rank match effectively provides percentile-based translation.

A Jefferson player can therefore graduate at 84 or 96 OVR while entering college at the rating appropriate to the corresponding recruit slot.

I added three historical values and the high school career remains legible after the player enters the college simulation.

hs_exit_ovr
hs_percentile
college_entry_ovr

Sparse headroom

Opening the high school scale leaves the ordinary population largely where it already lived. The additional space serves as a sparse upper tail. A very small number of players can generate directly into the new upper bands. Development can also carry exceptional careers into those bands.

The resulting shape remains concentrated through the familiar range, with progressively fewer players above it, The upper range exists while remaining sparsely populated.

In the first full-career-era census:

girls: mean 41.1, p90 61, p99 79, max 94
boys:  mean 43.3, p90 65, p99 84, max 100

Reworking the high school matchup curve

The development work also led me back to the match engine.

I wanted high school OVR differences to read in roughly seven-point competitive bands:

OVR gap | Interpretation

0–6 | peers

7–14 | modest advantage

15–21 | clear advantage

22–28 | strong mismatch

29+ | major mismatch

The shipped high school profile used skill_slope = 6.0.

A 3-point OVR gap produced about a 94.7% favorite.

Removing the existing hinge still produced about 92.9%, which showed that the slope itself dominated the outcome. The per-game edge accumulated through the games and sets of the match.

I lowered the high school base slope to 0.9 and replaced the single hinge with a continuous piecewise map using the 6 / 14 / 21 / 28 OVR boundaries.

Measured through the match engine:

OVR gap | Band | Reference rate | Measured

0 | peer | 50% | 50.1%

6 | peer | ~62% | 60.5%

14 | modest | ~75% | 73.2%

21 | clear | ~87% | 85.5%

28 | strong | ~95% | 95.2%

40 | major | 95%+ | 99.9%

College keeps its existing matchup curve.

The earlier high school profile had been calibrated against Oregon set-score distributions. The new curve produces a different scoreline distribution on the previous compressed Jefferson population. I plan to measure scorelines again after the new development era fills the association and the new talent distribution becomes the normal one.

The resulting lineup

With all four grades generated under the career model, No. 1 singles looks like this:

| 9 | 10 | 11 | 12

Before | 1.5% | 3.3% | 9.4% | 85.7%

After, girls | 13.3% | 18.3% | 26.7% | 41.7%

After, boys | 15.0% | 19.4% | 31.7% | 33.9%

The overall varsity lineup retains an age gradient:

Grade | Girls in lineup | Boys in lineup

9 | 42.1% | 45.1%

10 | 52.2% | 52.6%

11 | 62.2% | 62.3%

12 | 70.6% | 66.4%

Older players remain more likely to play, while underclassmen now occupy a meaningful share of the top positions.

Freshmen reaching the senior median rose from 1.3% to 8.7%.

These results differ from Oregon, as expected. Jefferson's talent model produces its own distribution. The Oregon data supplied an external reference for the general shape of high school lineup turnover.

What I am watching

The career model is gated by entry year, so the association phases into it over four seasons. During that transition I care most about the careers that appear during play.

Career-shape variety

I want to see a sophomore become important after a quiet freshman year, a JV player become a varsity starter, a highly rated freshman plateau, and a late developer pass older teammates.

Stagnation

Flat careers currently make up roughly 3–4% of the population. I want them to appear often enough to read as a recognizable career path.

Exposure

The sitting-to-JV-to-varsity gradient is now part of development. The next several seasons will show how clearly that difference appears in actual player histories.

Scorelines

The freed scale and flatter matchup curve both change the distribution of talent gaps. I will measure the resulting scorelines once the converted cohorts make up the full association.

The top of the scale

The current hard ceiling is 100. If exceptional players begin clustering there, the scale can extend further.

What changed

The old model produced players who improved on similar schedules toward destinations strongly shaped at generation. That kept roster hierarchy unusually stable.

The career model separates where a player begins, how much development is available during each year, how much of that development gets realized through playing, and the player's projected career level.

Two players with similar starting ability can now have very different four-year careers. One can arrive close to finished. One can make a large sophomore jump. One can develop steadily. One can plateau. One can spend several years as a JV player and become useful later. One can exceed the original projection.

A player who is ready at fourteen can enter the simulation ready at fourteen.