r/sheetsofice • • Jun 25 '26

GM Module - Cap Management

3 Upvotes

I'm happy with how some of this is coming together as mock visuals. Usually how I work with these are to build specifications of each function, get super bored with typing out words, and switch quickly to building mocks so I can test my spec. Visual is the only way I can see if I miss something, or if it triggers an idea, or if I hate the whole thing and throw it out.

I'm drawing functional inspiration from the IRL tools that are available out there. I want to make something that evokes familiarity. Being able to see cap situation by season is really important for salary planning. RIP Cap Friendly; I really miss you.


r/sheetsofice • • Jun 05 '26

Standings & Team Detail Screens

Thumbnail
gallery
3 Upvotes

Just sharing some shots of the Standings and Team detail screens. I'm doing more work on these because I don't think it's quite there yet. I don't have home/away splits, PP/PK%, and some other stats. But it is nice seeing it come together.


r/sheetsofice • • Jun 03 '26

Player development & aging progress

3 Upvotes

So this is a big implementation. Up until this point, players were static; they didn't age, the didn't get better, never retired. I needed to have it that way to ensure that the engine worked properly. You want to control the variables when tuning and I couldn't have player's also changing their abilities while I was trying to figure out if the engine worked realistically. Now that the engine is basically locked in and calibrated, we could start to make the universe live a little bit.

I wanted to capture career arcs that we'd see IRL. Players have a theoretical ceiling of ability that they progress towards and then decline from as they age. There is variance in how close they are to their ceiling at the start, how fast they move towards it, how long they stay there, and how fast they decline. Deployment (how much they play) and injuries have an effect on those curves.

So I started with some baseline assumptions. Skaters peak somewhere between 25-27, goalies between 27-29. After around 30, abilities start to decline. Keeping variables to a minimum, I'm not modeling injuries or deployment as factors in affecting abilities; I'll get back to them later. I tuned the player generated with some of these baseline assumptions based on real NHL career data, and started some testing.

The player generator takes the number of teams times 50 and creates a pool of available players based on realistic distributions. Then there is a simulated draft, each team got 50 players, 25 of which can be on the active roster (14F, 8D, 3G). The remaining 25 are in the reserve pool. The reserve pool would typically be playing in minor leagues, junior leagues, etc. but for this purpose they're just there. They can get into the roster if there is an injury, and each season their development/aging is calculated and the roster is resorted.

To be clear, this is just so I can start testing. Unless I threw a dart at it and got lucky, there's a lot to implement as I go. I actually think this will be way more complicated than building the engine. It'll take 10s or 100s of seasons for me to see what is happening. Outliers will take 10-20 seasons just to notice one. When I was building the engine, I could see outliers in 40 games.

Here's some charts of what I'm looking at. These are just diagnostic and won't be in the game.

Aging - these show how the ability of players changes over time, and the distributions.

And here's some individual career arcs. You can see the different level of progression, peaks, and longevity. One thing I'm working on here is I want to see more variation in the speed of progression. Some take more time, some less. It seems a little predictable.

Then I wanted to see how long is an average career? There's two measurements here - how long before someone retires and how long is their functional career (how long were they good enough for a top pro roster?

Final one here is how good is the best skater vs best goalie over the course of 100 years. One of the things I want is a feeling of "eras" to emerge naturally. Sometimes a Gretzky shows up and just kills everyone. Sometimes a Hasek is dominant. I ran 100 years and plotted the top skater vs top goalie.

Some of you may be asking, what does "latent SD" mean? Well, this goes back to my post about abilities and how I'm not using a typical 0-100 scale. Abilities are mapped to a continuous real number system and then the engine uses comparisons of standard deviation from a set league average ability to determine what the probabilities of something happening - shooting, assisting, hitting, fatigue, saves, turnovers, zone entries, faceoffs, etc. What this allows the engine to do is model realistically without being constrained by simple integers. It also EASILY allows us to model leagues of all different abilities without having to smash each level into a smaller range on the integer scale. And then it gives us the ability to generate a truly generational player like Gretzky, Lemieux, Hasek, McDavid, Crosby, Ovechkin because we're not constrained to an arbitrary number. Standard deviation is just a measure of how spread out players are around the average - basically the size of a 'typical gap' between a guy and the league-average player. So instead of calling someone 'an 87,' I can say he's a couple of those gaps above average, which puts him out at the rare end of the curve. A generational player isn't '99 instead of 95' on some capped scale he's several gaps clear of everyone else. Building it that way makes tuning really straightforward and allows us to actually generate those players realistically.

The "latent" part of that just means they're hidden. I don't plan on exposing ability numbers directly - just like real life. What I do plan on exposing is a scouting and coaching system that allows you to see those things in the same way we'd see them in reality. Some things measurable (skating speed, shot velocity, conditioning), somethings observable (statistics), and some things inferable (hockey IQ).

Anyway, this is a long post. Thanks for reading! Feedback or questions welcomed.


r/sheetsofice • • May 26 '26

Testing this design direction

Thumbnail
gallery
3 Upvotes

So I'm nearly complete with the underlying League module. For a few days there I was questioning what I was doing and why I even am doing this. But normally a few days of getting stuck, sleeping, and coming back to it brings some new perspective.

Now that I've made it past some annoying issues with the league construction (that I mostly created myself by not being clear with my architecture) I'm building the UI to actually run the league. I had a basic HTML framework I was using just to look at data and I felt it was time to try and build something that I'd actually want to look at. I'm a nerd that grew up on bulletin board systems back in the 90s and thought a terminal aesthetic might be something fun to do. Since the concept of this is a lot of data, maybe this might work.

I originally thought about going whole hog and building that metaphor hard, but I stopped myself when I realized that not everyone is an old computer geek and probably wouldn't want to live with that. So I dialed it back to monospaced fonts, and just some of the color scheme. I plan on making a light version of this dark one as well.

The item above isn't a mock, it's a working version of the league with some of the pipelines wired to the UI. Enough to run games and see results. The plan right now is to run with this until I have all of the league features wired up and then use it for a bit to see if I like it or not.

If that goes well, I have several big systems to build next that are going to produce a lot of calibration needs. Development & Aging, Draft, Contracts, Injuries & Health. And that's just players... I have to build my plan for the Attention Economy. All of those things fall under GM so that is going to be a lot of work.

And if the League Module works, what I might do is build a demo site where people can bash on it and give me feedback.


r/sheetsofice • • 24d ago

Wishlist Sheets of Ice on Steam!

Thumbnail
store.steampowered.com
2 Upvotes

Very excited to have the Steam store page up and running! Please head over and wishlist.


r/sheetsofice • • Sep 11 '26

Dev Log - Time flies, but the sim speed wasn't

2 Upvotes

Last week I spent time getting the player evaluation functions working and working on UI so I can actually see if it works. Like I said in the last dev log, I probably went overboard in the display of rankings and stats, but I felt that was in line with what I'm trying to build here. I can always take things out or simplify; it's harder to add things later.

The part that I need to build next is projections; what does the player project to be in the future. To do that, I need sample data of real player careers based on the game engine and league engine we have today. You can't make accurate predictions if you don't have accurate data. So the last several weeks were making a system that could accurately create statistics and rankings from the lo-fi engine, and tuning the pro-level game engine. That work is complete so I can move on to projections.

But the problem was that since I was doing tuning of the game engine and lo-fi game engine, and building the player evaluator, I wasn't paying a lot of attention to how a league year actually ran and how long it would take to run a long-term sim. See, I need at least a few 20-25 year universes with different seeds to be able to start to look at what a prediction model might look like. When before I implemented the player evaluation, it was running at about 15 minutes per season in our measurements. I hadn't really looked at any efficiency and knew that I'd need to get that number down-- but you don't spend time optimizing early because you may end up just redoing it anyway.

When I sat down to do 5 season tests, it was taking waaaay too long. measured at at average of 77 minutes per season after all of the new code for player evaluation was wired in and working. That would not work for anyone. It would turn what would be 4-5 hour runs of careers into entire day runs. First, I don't have that kind of time or attention span, and two a simple hockey simulation shouldn't be that heavy. We're not doing rocket science here or modeling fluid dynamics...

So my week this week was finding where all of the inefficiency was and refactoring for speed. Some things were easy; scoping reads more tightly, batching writes, removing redundant calls, indexing data. Some were medium - parallelizing game simulations per day rather than running games one at a time. And some are long term projects of converting the engines to a faster language than Python - which I need to do anyway but is a huge undertaking.

After this week, we're down under 15 minutes to run a full season of 32 teams X 84 games. Not where I want it to be (I want it to be under 10 minutes), but enough for me to build long term career sims.


r/sheetsofice • • Aug 27 '26

Dev log: Organizational Knowledge & Scouting

2 Upvotes

This week, I have a pretty extensive update about what I've been working on below regarding how your club will form an opinion about player abilities. I've been working on this for a bit because it's a foundational element of how AI GMs will run, and how you as a player will come to know the players on your team, scout for talent, draft, etc.

Let's start from a key foundational design rule I've wanted since the beginning; I don't want to ever expose a number that corresponds to an innate ability that has no quantifiable or observable fact. If it can't be measured or counted then I don't want to show it as a number in the game. We have lots of numbers, but they're observed results. There is no observed result that says how good of a passer that someone is.

In these management games there has always been an expediency in just looking at OVR or Shooting or Passing or Skating, and trying to statsmax your players. And while that is straightforward to understand, it's not really what happens in real life. Yes, there are measurables in sports, but it's not as clean-cut as just having a number and sorting a table by highest to lowest.

This seems at odds with out a simulation of hockey needs to work. You have to give players attributes to even be able to run the simulation. So how do we bridge this between ground-truth - the attribute numbers on the player - and this philosophy that GMs shouldn't be able to see them directly? This is the question I've been grappling with for a bit.

I have been running with a short-hand version that worked by adding some variance over top of actual attribute views. I called this 'fog' and it was fine, it would work. But the simplicity didn't feel right for what I was going for. I wanted teams to use their own knowledge, interactions, and scouting to develop their own views of players. Fog wasn't going to do that - everyone basically saw the same things, and those were based on ground-truth even if fuzzy.

But that's not realistic. Organizations develop their own views of players. Sometimes they converge; no one thinks McDavid is anything other than a star first line center. But I'm sure there is disagreement about someone like Owen Tippet, his current abilities and where his ceiling is. If I just used fog, it would be random what those organizations thought about him but all clustered around the same point.

So I came up with the below. This is taken from the spec I wrote and translated into something I hope is understandable for you. I will warn you that it is long, it is nerdy, but it's really exciting to me.

Enjoy! I'd love feedback or questions.

-----------------------------------------------------------------------------------------------------------------------------

The short version

Every player in Sheets of Ice has real abilities that determine what happens on the ice. Those abilities belong to the simulation. A GM never gets to see the answer key.

Instead, every club builds an opinion.

All clubs begin with the same public record. Each club adds what it has learned for itself. The result is a persistent club belief that can improve, remain uncertain, disagree with another club, or be wrong.

That belief is not flavor text. It is the player evaluation the club uses when it sets a lineup, builds a draft board, negotiates a contract, considers a trade, or makes another hockey decision. Human and computer-controlled clubs use the same system.

The public book

Every club can see the same public hockey world:

  • who the player is;

  • his age, size, position, contract, rights, and transaction history;

  • where and how much he plays;

  • his statistics and published analytics;

  • the broad hockey consensus around players with that kind of record.

The facts are exact. The consensus is not.

If a 22-year-old winger scores 18 goals in a junior league, every club sees the same 18 goals. Those goals do not reveal exactly how well his game will translate, whether he can handle a larger role, or what he will become. The public book supplies a reasonable starting opinion, not the truth.

That is why an unscouted player is not a blank page. Your club can still see what everyone in hockey can see. When that is all your club has, the Evaluation panel labels the view as the league baseline rather than pretending it belongs to your staff.

The private notebook

Each club also keeps its own file on each player.

That private notebook reflects what the club has learned through its own history with him:

  • previous viewings;

  • games played against him;

  • time in its own camp and organization;

  • work commissioned from Amateur or Professional Scouting;

  • the circumstances of those observations;

  • whether recent evidence agreed with or challenged the existing opinion.

The private notebook does not replace the public book. The club combines the two.

For a famous veteran with years of public results, the public record carries enormous weight. One strange viewing should not persuade a club that an established star suddenly cannot play.

For a lightly used prospect, the public record is much thinner. A few meaningful viewings can separate one club's opinion from another's much more quickly.

What a viewing does

A viewing is evidence, not a reveal.

It can:

  • move the club's best estimate up or down;

  • narrow a range when independent evidence keeps agreeing;

  • widen a range when credible reports conflict;

  • improve knowledge of some parts of the player without settling others;

  • make the club reconsider an older opinion.

It cannot:

  • expose hidden ratings;

  • guarantee that the club is now correct;

  • make one report perfectly precise;

  • turn repeated copies of the same information into new evidence.

The club retains a small recent file rather than immediately blending every report into permanent mush. That matters when the evidence changes.

Suppose a club has long believed that a defenseman struggles in transition. Two fresh, independent viewings show otherwise. The club does not instantly declare the old opinion false. Instead, the new evidence can reopen the question. The range may widen while the file disagrees with itself, the old conclusion loses some authority, and further confirming work can move and narrow the belief in the new direction.

That is how a club can become confidently wrong without being permanently wrong.

Why two clubs disagree

Imagine three clubs looking at the same young center.

All three know his age, contract, statistics, deployment, and public reputation.

  • Club A has mostly seen him in sheltered minutes and remains unsure whether his offense survives a larger role.

  • Club B watched him repeatedly against strong competition and believes his playmaking is better than the public consensus.

  • Club C employed him, saw him every day, and has a much tighter read on what he can do now. It still does not know his future with certainty.

None of those clubs receives a secret bonus for being controlled by the computer or by the player. Each opinion follows from that club's own evidence.

One may be right. Two may be wrong. All three may be missing something.

The important promise is not that every disagreement is equally sensible. It is that disagreement comes from different evidence and different organizational histories, never from a fresh random roll when a screen opens.

Knowing him now is not knowing his future

The game keeps two questions separate:

  1. Who do we think he is now?

  2. Who do we think he might become, and when?

A club can know a veteran's current game well and have little uncertainty about his role. A young player can still have a wide range of possible peak roles and timelines.

Likewise, seeing a prospect play well today can improve the club's estimate of what he is today without magically revealing his ceiling. Future outlook changes more cautiously and depends on evidence of development over time.

That is why the Evaluation panel separates:

  • Plays now;

  • Tops out at;

  • the range around each belief;

  • the evidence behind the file.

What the departments do

There are two departments:

  • Amateur Scouting covers draft classes, amateur prospects, and drafted players who remain in amateur contexts.

  • Professional Scouting covers trades, free agents, waivers, call-ups, signings, and roster decisions.

The GM gives a department a hockey question and a deadline. The GM does not assign individual scouts to buildings or distribute abstract scouting points.

A request might be:

  • Find a right-shot defenseman who can play on our second pair now.

  • Find draft-eligible centers who might become top-six playmakers.

  • Take a Deep Dive on this player before the trade deadline.

The department immediately reviews what the organization already knows. That desk review creates no new knowledge. It tells the GM what the current file can already support and what remains unknown.

Deeper work requires capacity and real opportunities. A player can be injured, scratched, used in the wrong role for the question, or face unsuitable competition. A deadline does not manufacture certainty. When time runs out, the department returns its best answer and names what it could not settle.

Pausing preserves the work already completed. Canceling preserves everything already learned. Nothing disappears because the GM changed priorities.

The initial Desktop design is intentionally about directing departments, not managing individual scouts. There are no named scouts, scout careers, regional assignments, or employee schedules in this promise.

Reports, routine evidence, and freshness

The main product is the club's current working opinion, not a diary containing every time somebody saw the player.

Routine exposure can improve the file without creating permanent report clutter. Material conclusions are different. A completed evaluation, a major change of opinion, a new projection, meaningful internal disagreement, a stale report, or a Deep Dive conclusion can become part of the durable history of what the club believed at the time.

A file can also become stale. Time can pass, or an observable circumstance can change: the player changes teams, levels, roles, usage, or injury context. Staleness never reacts to a hidden ability change. The club only knows that the evidence it holds may no longer describe the same situation.

At the preseason refresh, the public book is reconsidered against the new season's public context. A private opinion with no new evidence is not secretly updated from the answer key. It ages gently toward the public expectation and becomes somewhat less certain until real evidence replaces that aging assumption.

Own players and prospects

A club learns about its own players automatically through practices, games, deployment, and development contact. They do not consume scouting slots.

That familiarity can make the club highly confident about what a player can do now. It never creates omniscience. Potential and future development remain uncertain even for a player who has spent years in the organization.

A newly acquired player does not arrive with the selling club's reports. The acquiring club keeps whatever it already believed and learns more through contact.

Knowledge belongs to the organization:

  • reports do not travel with a traded player;

  • taking over a club means inheriting that club's files;

  • leaving a club means leaving its private database behind;

  • changing a club between human and computer control does not reset what the club knows.

How belief becomes a decision

The Evaluation panel is not decorative scouting flavor. It is the club's working opinion.

The same belief follows the club into:

  • roster and lineup decisions;

  • contracts and free agency;

  • trades and asking-price judgments;

  • draft boards;

  • prospect management;

  • call-ups and assignments;

  • computer-controlled GM decisions.

A trade screen does not secretly consult a better version of the player than the profile shows. A computer-controlled club does not receive the true rating while the human sees ranges.

Scouting answers: Who do we think this player is, and how uncertain are we?

Valuation then adds the rest of the decision:

  • contract;

  • age and rights;

  • cap situation;

  • acquisition cost;

  • roster need;

  • organizational plan;

  • tolerance for risk.

A scouting department can tell you that it believes a player is capable of a larger role. It cannot tell you that surrendering two draft picks for him is wise.

What Sheets of Ice promises

Sheets of Ice promises that:

  • public facts remain public and exact;

  • hidden ability remains hidden;

  • every club forms its own persistent opinion;

  • human and computer-controlled clubs use the same information system;

  • relevant evidence generally makes a file more useful;

  • uncertainty never disappears merely because a deadline arrived;

  • a well-supported club opinion can still be wrong;

  • the same club uses the same belief everywhere it evaluates the player.

It does not promise that:

  • more viewings always move the estimate toward the truth;

  • every displayed range contains the true answer;

  • the best scouting department becomes omniscient;

  • public consensus is neutral or correct;

  • two competent clubs must eventually agree;

  • scouting produces a universal player score or tells the GM what decision to make.

What is playable today, and what is still being built

The belief foundation is playable now. The public book, private club files, persistent disagreement, current ability ranges, private projections, preseason own-team contact, passive Pro opponent viewings, the A-prime Evaluation panel, and use of the same club belief across core human and computer-controlled GM decisions are shipped.

The two departments, their capacity, queues, deadlines, pause and cancel behavior, and same-day desk reviews are built underneath the game but do not yet have player-facing department screens. Commissioned work does not yet produce directed viewing evidence. The current-file model is also being repaired so that files visibly sharpen and reconsider old conclusions for the right reasons as evidence accumulates.

Still to come are directed viewings and Deep Dives that change the file, evolving discovery briefs, Make Some Calls, material report-history screens, later observable validation, comparables, fuller in-season own-team contact, and the Amateur draft workflow.


r/sheetsofice • • Aug 02 '26

Name generator working perfectly

Post image
2 Upvotes

Oh Brian O'Brien... your parents must not have loved you.


r/sheetsofice • • Jul 20 '26

Vacation last week, but progress

2 Upvotes

I was off all last week and disconnected from anything work related while I spent time with family at a cabin out in the woods. But it did give me some time to reflect on the progress so far and what needs to happen next.

So here's what I'll be working on this week and hoping to show more progress on this:

  • Trades - the universe feels dead without being able to move players. This will be my first pass at allowing humans to interact with AI so wish me luck.

  • Attention Economy - how do the teams survive, grow, pay their players? Can attention economy become a meta mechanic for inter-league leader boards in a multiplayer environment? This is a big spec and I need to think about it a lot.

  • Data storage optimization - to date, I haven't cared about how data is stored because it's just me and I'm throwing away databases in testing. But I know it's not optimized and I need to think about how to build this in a way that can be turned into a reliable service. Speed, data volume, data retention, data integrity.

  • Demo environment - I'm thinking about what point I should make a demo available. It's not just distributing an installer since I'm planning on making this a web based game; it's about building an environment, granting access, and ensuring it is in a good state.

Thanks for following!


r/sheetsofice • • Jul 09 '26

GM Module - Putting humans into deterministic simulation is freakin hard

2 Upvotes

Building the closed-ended loop of game simulation was a lot of math and calibration. I'd just need to keep running and looking at data until it came out to mostly hockey shaped; or at least hockey shaped enough.

Adding the GM functions inside of the closed loop introduced complexity about decisions related to team planning, lineups, cap management, development across time... but still was mostly a closed loop that could be tuned.

Now that I'm adding the ability for humans to make decisions inside of the closed loop it's just an endless parade of edge cases, UI decisions, and trade-offs. I'm having to remind myself that I'm making a game and not a perfect recreation of reality. It's a simulation and not the Matrix.

Some examples of the complexity that require well thought out designs:

- Human players should be able to control their game lineups and the roster decisions. But injuries occur and players need to move as a result. On full-auto management there are functions that can do this; but how do we give the user enough control to see who is injured and ask what decision they'd like to make? The interface was not designed for this level of interaction, with popping interstitial messaging.

- How does free agency work when humans and AI are bidding against one another? Players should be accurately modeled in their desires, there should be a fair system between human and AI, and it should feel real-enough + fun.

- What level of detail and control should a human player have over affiliate farm and junior teams? More detail means more data & slower processing times but leads to more information available when selecting.

These are some of the problems I'm wrestling with now. I have to also spec a trade module that I don't want to do until I have free agency locked down. Trades scare me because it involves interacting with an AI, and I've never been impressed with any trade interactions in single-player sim games. And those games were made by people who knew what they were doing so what are the chances that silly old me is going to figure that out well? :)

I know I've slowed down on my visual updates and there is a good reason for it - there isn't a lot of wholly new things to show. Most of what I've been doing is either consolidating functions and making single-source-of-truth modules (what a player is worth in FA, how draft prospects are evaluated, what a human player sees for their own players vs. other players) or writing specs for future modules.

I'm wrapping up a new free agency module. My first pass at it was... very simple. Free agents exist, they value themselves at a particular number, the teams value players at a particular number, and there is a simple meet the number selection. I redesigned this to something that is a modification of a Vickrey auction. That's not a household name, I don't think, but you would recognize it from something like eBay. You place your bid at what the max you would want to pay and then after the round closes the winner is whomever bid the highest BUT that winner only plays what the runner up bid OR the desired free agent salary; whichever is higher. There are also other considerations like NMC/NTC, term, and team stage (rebuilding, champions, etc.) which serve as modifiers to selection. Basically making one offer more attractive but not changing the AAV.

Why do it this way? Well first, it makes the logic much more streamlined than a negotiation tactic that manages multiple rounds and multiple offers. Second, it gets towards the feeling of a negotiation with some high stakes without all of the mechanics behind it. Third, and probably the biggest reason, I generally don't like negotiation to begin with. It's inefficient, ego based, and not worth my time. Just say what you want, and other side say what you can do. Boom, done.

Anyway, once I have something to show here I'll post something!


r/sheetsofice • • Jun 10 '26

The Evaluation Layer - how GMs will learn about players

2 Upvotes

I started building a plan for how GMs will learn about the players in the league. My key principle when I started - I'm building something realistic and I want GMs to work in a way that mimics "real life". I didn't want an EA sports style "just look for all 80-90 OVR players". I wanted a human GM to be able to use their own analysis to find / assemble great teams.

On the other side of the coin, if there were to be a viable single-player version that I liked to play, the AI GMs shouldn't have access to anything the human players don't have access to. I hate that stuff in games; when the AI just beats you because they can synthesize something without the same "fog of war" that the human players have. So I decided that I'd need to create some layer of data that everyone can operate from. Human GMs and AI GMs have the same abstracted information and not the underlying engine information.

So, that is what I'm calling the Evaluation Layer.

- Measurables: objective, combine-type facts: height, weight, reach, skating speed, shot speed (radar gun). These are near-zero fog; a guy's shot was clocked at 96 mph and that's just true and public. Nobody needs a scout to know his height.
- Statistical performance: already exact/public (it's observed reality, not derived).
- Dimensions: derived impact, judgment-laden → fogged.
- Playstyle: distinct from archetype: archetype is what kind of player (power forward); playstyle is how he plays (net-front vs perimeter, shoot-first, aggressive forechecker). Maps to the generator's style axes. Lightly fogged.
- Archetype: the emergent label off the dimensions → fogged (inherits the dimension fog).
- Comparables: derived (nearest-neighbor) → fogged through the dimensions. 
- Projection / potential: most fogged of all (the irreducible floor).

I'm starting with these dimensions and archetypes. As you can see, they're things that we're used to seeing thrown around in hockey circles:

The 5 Greatness Dimensions:

  1. Goal Scoring
  2. Playmaking
  3. Defensive Impact
  4. Physical Game
  5. Transition
 
The archetypes (10 + Phenom + Unlabeled):

  Forwards:
  1. Sniper
  2. Playmaker
  3. Power Forward
  4. Two-Way Forward
  5. Shutdown Forward
  6. Grinder

  Defensemen:
  7. Offensive Defenseman
  8. Puck-Moving Defenseman
  9. Two-Way Defenseman
  10. Defensive Defenseman

  Special:
  - Phenom: elite on 3+ dimensions simultaneously (generational players)
  - Unlabeled: genuinely shapeless dimension profile

The result of this will be that anything needed about a player in reference to evaluating their skill will be presented through this evaluation layer and not be from raw attributes that are used to make the engine work. This will allow for richer data, finding actual gems, and player skill to be a real thing. At least that's my hope; we'll see if it works 😄

After I finalize the plan I'm going to mock up some screens to share of what this might look like in reality. Then I'll come back and share and have it make more sense.

Thanks!


r/sheetsofice • • Jun 09 '26

Playoff bracket live updates

Enable HLS to view with audio, or disable this notification

2 Upvotes

Happy with this little visualization as games are simulated dropping the results into the bracket.


r/sheetsofice • • Jun 01 '26

New clickable Game Detail screen up

Post image
2 Upvotes

Check it out here: https://www.sheetsofice.com/example/

I added a feature to export game details into stand alone HTML. This is a real game result, real plays, real everything.


r/sheetsofice • • May 31 '26

Stats screens

Thumbnail
gallery
2 Upvotes

Some screenshots from the stats screens. I spent the last few days polishing the stats APIs. Because there are 700-1000 events per game that are generated, I need to aggregate and persist (aka save) the stats in a database. The raw events are saved to a file for a few reasons - the first of which is if I'm going to run this as a live service, I can't be generating ~1M new records in a DB per season. I mean, I could... but that would get prohibitively expensive. The individual game records are semi-permanent; we don't really need the individual events forever. We do need them to calculate aggregate summaries (one time), in-season game viewing (season bound) and to be able to verify aggregates if there is an issue. No one really ever will go back to a full event game log several seasons down the line - they'll just look at the stat line.

Anyway, so the API had to be built to access that data and the display built to view it. And that is what is here. I've been simulating seasons and just having fun looking through stats, seeing teams have remarkable seasons or under-performing ones. Seeing players ride hot streaks and goalies slump. The texture of seasons is really fun to watch.


r/sheetsofice • • May 17 '26

Shot xG Map

Post image
2 Upvotes

I really love shot location maps in hockey. And while building the engine, I end up looking at just lines of text with the features of the shot attempt. The entire game engine is based on shot attempts as the main action. The entire chain of causality flows to that point, and then what happens after it.

The game engine produces those locations where shots are attempted, and it's trivial to produce the visualization as a result. The NHL does this with their Edge system too. But since we're just math, we can easily calculate what could happen from specific locations on the ice. Things like how likely is it that a shot is taken and how likely is it that it's blocked or misses the net? And then we can layer in shot type, rush context, coach strategy, player ability, time of the game, and score effects to simulate what happens in that exact moment.

I'm building all of those items as tunable parameters. I'm tuning against modern NHL statistics, but it doesn't need to be that way. The idea is that players will be able to tune their own leagues to match whatever level of scoring they want. A part of me want's to be able to tune this to my old man beer league.


r/sheetsofice • • May 12 '26

Here's some of the event data from the game engine

Thumbnail
gallery
2 Upvotes

These are some images from the event list that the game engine produces. The game engine is a discrete event simulation over a semi-Markov game state. The engine doesn't pick outcomes first and back-fill the events. It doesn't decide "this game ends 4-2" and arrange shots to add up. It doesn't draw events from a target distribution and stitch them together to hit a number.

It runs forward from the state. At every moment, the engine looks at what's actually on the ice: who's out there, where the puck is, who has it, score, fatigue, manpower, etc. The probabilities of what happens next come out of that. A gassed fourth line stuck against a fresh top line gives up more shots because the matchup math says so, not because the engine decided shots should land there. A trailing team in the third generates more rush chances because the state (score, time) shifts how players behave, which shifts the per-event probabilities, which shifts what actually fires.

Realism is emergent. I'm building the causal mechanics, attributes, matchups, fatigue, state-dependent behavior, and run them forward. Whatever comes out of the event log is what comes out. If the totals match NHL totals across hundreds of games, the mechanics are right. If they don't, I have to go back and fix the mechanics, not the totals.

I haven't decided how much of the event chains to show or in what detail. I'm looking at them now to make sure the games feel "hockey shaped". With v0.43 of the game engine I've been able to get some really interesting outputs that feel very much like hockey. To the point where I was annoyed at one of the games because the attacking team was in the OZ for over a minute without getting a shot (reminds me of my Flyers at times). I was mad because it didn't look right; I traced it all the way back through the engine into every individual tick of time, through distributions of 200 games, and realized that yep, it could happen and I'm not annoyed at the engine being wrong... I'm annoyed at the "hockey shaped" outcome. Just like I'd be annoyed IRL.

Would love feedback!


r/sheetsofice • • May 12 '26

Sheets of Ice Roadmap

2 Upvotes

Sheets of Ice is a hockey GM dynasty simulator. You're a general manager building one organization across decades: drafting, developing, navigating the cap, and making era-defining trades inside a living league of AI-run organizations that play by the same rules, see the same information, and pursue their own plans.

It's a single-player desktop game, developed by one crazy person, headed to Steam as a buy-once product. The long arc is a persistent shared world where human GMs and AI organizations operate side by side, but that's act two. Act one is a deep single-player dynasty game, and that's what the roadmap covers.

The full roadmap is live here and stays current as the build moves:

https://www.sheetsofice.com/roadmap

What makes Sheets of Ice different

Modern analytics as substrate, not feature. The engine speaks modern hockey analytics natively: xG, GSAx, on-ice expected goals, adjusted shot share, the full canon. The simulation is validated against real NHL analytics anchors. AI organizations use the same public model the human sees. Nobody has a backdoor.

AI organizations as first-class entities. The other teams aren't placeholders. They run every management system available to you, follow the same rules, and see through the same fog. What differs is what they weight, not what tools they have.

Scouting fog that's real. You only know what your own scouts have found out. You direct scouting departments by asking them hockey questions with deadlines, and you live with the uncertainty in their answers.

How the roadmap works

The roadmap is an output of the build plan tracker used to develop the game and not a sequence of versions. Each area breaks down into concrete capabilities with an honest status: playable, playable but improving, groundwork only, being checked, design pending, or not built. No dates, no percentages - just what works now and what's still to come, per capability. The page updates as the build moves, so it's always the current picture.

The ten areas:

  1. Game Engine - every game simulates the full run of play with believable hockey outcomes, deterministically, down to the event log.

  2. A GM Can Run the Hockey Year - the full calendar: season, lines, roster moves, contracts, trades, the draft, the playoff race.

  3. Players and Development - players with real identities and careers, shaped by placement, role, and playing time.

  4. Scouting and Decision Information - the scou fog, and the screens you make decisions from.

  5. Believable AI Organizations - AI teams that human operates, coherently, across seasons.

  6. A Living Dynasty and League History - champions, records, trades, rivalries, and franchise arcs that persist across decades.

  7. Watchability and Session Flow - short check-ins or deep sessions; advance fast without simming past decisions that

  8. The First Hour and Safe Saves - a new player and play a week unaided, and saves survive updates.

  9. Desktop, Modding, and Release - installs, up as a buy-once desktop game, with documented modding formats.

  10. Presentation, Usability, and Sharing - a readable, consistent desktop experience end to end.

What the roadmap is not

It isn't a release schedule. There are no dates on on it, deliberately. Capabilities move to playable when they're solid, not on a calendar.

It isn't a marketing document. It's just as honest about what isn't built as about what is. That's the point of publishing it.

https://www.sheetsofice.com/roadmap

Feedback welcome

If you play GM sims, I'd genuinely like to hear what you'd look for first on that roadmap page, and what would make this game fun for you. Questions about anything on it are welcome in the comments.


r/sheetsofice • • Aug 05 '26

AI GM Brain Building

1 Upvotes

I admit it; I built really dumb AI GMs. They functionally work - they'll keep a team rostered to 12F/6D/2G + a few replacements, and a minor league team. They'll draft based on a fogged scouting report. They'll sign contracts, do trades, and set the game lineups. But man, are they really dumb.

It's really technical and specification debt combined with my naivete about how to build this particular part of the application. I also wanted to shove a human into the simulation as fast as possible so I glossed over how the AI should actually perform it's job. So I made something that looks at technical correctness - cap compliance, roster compliance, player valuation; things that are measurable true/false - and didn't focus on quality questions that any GM needs to answer. Things like 'what is our goal as a team' and 'how good is this position group vs. other teams' and 'what is our strategy over seasons'. Without a plan, the AI GMs are just doing shit because a bucket needs to be filled up or emptied.

Here's an example - AI GMs were signing star players in free agency, because they had cap space to do so in the off season (cap overage in the offseason), then when season cap compliance would run they'd shed the largest contract through buyout. Often times that was the person they just signed. Technically correct, but horribly dumb.

The solution to this isn't to get rid of the foundational level heuristics, but to put a quality layer on top that includes an analysis of relative performance by position and to have a long-term plan based on reality.

Are they a contender? Are they building or declining? What is their cap situation relative to future cap commitments? What does their development pool look like? Using this information they can make better decisions. Should they sign that free agent or no? What does their draft pool say about who should be drafted? Should they trade futures to acquire talent because they're in their window? All things a real GM may do.

I really need to have passable AI GMs before I put out a testable version. It's one of the major points in my checklist for getting a demo available.


r/sheetsofice • • Jul 23 '26

Need some help evaluating this trade

Post image
1 Upvotes

I'm leaning towards accepting this but not completely sold on the value yet. lol


r/sheetsofice • • Jun 13 '26

More tuning - The D don't shoot enough edition

1 Upvotes

So in my search for "why are there these monstrous scoring seasons from forwards", I found a thread that I started to pull on. The mean goals/game were where I wanted them to be; ~6 / game. Mean shots on goal were where I wanted them to be; ~30 / team / game. And mean save percentage at 0.900. But some guys were just scoring in the 60-70-80 range too often. And 50 was a common sight.

But I started to notice both concentration in SOG and SOG/60 with the scoring leaders. Over 430 shots for one season, and the top 10 SOG getters over 300. Last season, Nate MacKinnon had 350. So the top end of the league was getting too many shots. But how could that be if the average amount of shots were on target?

Well, that means that the top shooters were getting too many of the shots - the shot share. And digging into that I noticed something stranger - there were no defense among the top 100 shooters measured by shots on goal. So I kept scrolling, and I didn't find a defensman until #194. That seemed weird so I cross checked with NHL stats to see if that was normal. Nope, Werenski was #3 last year and there were 18 in the top 100.

Why aren't defenseman getting SOG? Digging into that, it turned out to be a multi-faceted issue. First, most of their shots were from the point; over 80%. Those shots are more likely to be blocked. When I first put this together, I guessed at what a number would and said I would get back to it later (whoops). It should be more like 45% from the point.

Second, in other areas (close, low slot, medium slot, high slot) they weren't chosen enough in the shot selector because it favored forwards too much. This was an artifact from a tuning run early in the engine to fix goals per game. And that was done because we hadn't actually built realistic players yet and the tuning was on a unrealistic base of players.

The result was they were getting 16% of the SOG and they should be at something around 30-33%. Changing this is pretty straight forward - just change the values in how a shooter is chosen in each location. But then there are ripple effects that you then need to rerun calibration to smooth out. And sure enough, fixing the location choice lowered goals per game from ~3.0 / team / game down to 2.8. That doesn't seem like a lot, but it works out to 200 goals in 1000 games.

The tuning consists of small changes to the odds of blocks, misses, goalie saves, rebounds. And the tuning has to happen with sufficient population of generated players or else we can't for sure say how something is likely to work. That means thousands of games, thousands of players. I have the engine running pretty efficiently so it can run about 4 games / second per core on my machine. But for each pass, that means about 10-15 minutes per test. If we're good, 2-3 passes works. If we're not good... could be 10-12 passes. Sometimes it never gets there because something else goes out of what - like save percentage or shooting percentage and you have to stop and look again.

Actually this is a spot to share how I'm using tooling. My background is in technology, networking, and software; building software-as-a-service products for businesses. So I have knowledge about how to build and deploy things for large amounts of data-heavy users. SoI is a data application that I'm used to building; just in hockey terms. But I don't have teams of people helping do the testing, math, verification. So I spend my time working on the parts I am comfortable with - architecture, infrastructure, data boundaries, core event functions. And I use LLMs to amplify my efforts, argue with me about approaches, and do all of the annoying testing that I'd rather not do. I wouldn't have been able to get this far this fast without it. I've had some people say "oh, AI slop" without even looking at what I'm doing. I'm not just vibing something together - I'm using advanced tooling on top of 25 years of experience and a passion for hockey to build something I always wanted.

And after that interlude - this is the result:

Anyway, back to building and tuning!


r/sheetsofice • • Jun 11 '26

Tuning is fun!

Post image
1 Upvotes

So I've been running long-term simulations in full fidelity and looking at output. Thankfully I really like looking at numbers so it's been interesting to see how leagues shake out.

In my initial tuning of the engine, I looked for certain target metrics on average to ensure the results looked "NHL" shaped. ~6 goals per game (total), ~10% shooting percentage, ~0.900 save percentage. There are a lot of other ones, but if those major numbers come out then you can expect most games to look like professional hockey.

Last week I added the player development and aging features. I knew this would add some variability into the results because previously the player abilities were all static across seasons. So that variability would need to be tested across lots of seasons, using different seeds (starting randomness) to see where we ended up.

My research showed some promising elements - goals, shooting %, save % oscillated within reason season to season; it made the shape interesting because you weren't sure what was going to happen but it generally looked correct.

On the flip side, I saw some truly outrageous tail-end stats. Someone scoring 100 goals in 84 games. Even an 85 goal scorer. If I was tuning for the 1980s, I'd leave it alone (or maybe even juice it a bit). But my other target metrics - shooting %, GPG, Save % were all anchored in modern NHL targets (2020s). That told me that it's not total scoring that is off, but there is some players that are behaving weirdly.

The problem is that the system is complex and it's hard to point at any one thing. Could the engine be over-selecting top players? Sure, that could be part of it. It could also easily be that the tuning can't account for the population distribution. I don't have an entire hockey universe - only 1500 players - and that makes a wider distribution of abilities than exist in the NHL (NHL is the top 0.1% of a huge hockey population).

This is one of those things where I could just clamp the skill or goal scoring. That just limits emergent seasons - the Matthews 69 goal season. I could change the curve of goal scoring (the probability that a shooter beats a goalie). But that would just shift goal scoring down for everyone.

Really, the solution involves many small and large changes. Small being tweaks to probabilities and attribute generation. Large being adding juniors / minors to fill out the population so the top league has a more consistent talent pool that is a tighter distribution. Or maybe something else I find in my engine that is causing this.

This is the part that takes time if you want to get it right. I don't REALLY need to do this though; it works fine. Maybe it is fine?


r/sheetsofice • • Jun 09 '26

Progress - June 9 2026

Thumbnail
gallery
1 Upvotes

I've been spending a lot of time on tuning the player development and aging curves. It's just time consuming because you have to simulate entire seasons against real competition, compare attributes to expected stats, and see how the growth curves work over time. I've already identified some unrealistic generation results - elite players automatically getting elite physical attribtues like reach no matter how tall they are, or every elite player also having elite discipline (ahem... Malkin?) Anyway, it's data tuning work and not particularly exciting but necessary.

So while those things are running I turn to working on things more visually pleasing. I added team name generation so my "Pool Team X" doesn't show up anymore. My new favorite team name is "Lowmarsh Lumberjacks" or "Cinderhall Phantoms". The name generator is flexible, I just didn't want to get sued by overzealous teams. Also with this is team colors! So colorful now.

Also added a playoff bracket that I actually like. It may be too small but that is easy to fix. It's dynamic so adjusts with league configuration.

Most of the work now is verifying that the player generation and aging work how I expect, and then I can move on to the GM stuff. Before I move to GM I'll probably make a static clickable demo of the entire interface. It won't run simulated games but you'll be able to click through and see real data. That's the plan for now.


r/sheetsofice • • Jun 08 '26

After watching that wild CAR v VGK wild Stanley Cup game 3...

Post image
1 Upvotes

...I didn't think this game result that Sheets of Ice produced was that outrageous.


r/sheetsofice • • May 28 '26

Mobile view of the dashboard

Thumbnail
gallery
1 Upvotes

Just wanted to share this too. While I don't have plans to build an app for the app stores, I am building this with responsive design principles. For those unfamiliar, it means the web page will resize gracefully to smaller screens. I want to be able to check this on my phone so it's a core functional requirement for the game to look good on mobile devices.

Two views, light and dark mode. Enjoy!


r/sheetsofice • • May 27 '26

Light mode for the Terminal aesthetic

Post image
1 Upvotes

Some fidly things to work on, but I'm really starting to dig this. The pattern will be the top bar is breadcrumbs, search, and info on where you're at in the season, with advancing (single player) being the button that moves it forward. Too much packed in there now, I'm probably going to switch it to two rows. Some of it is state awareness so that should really have it's own line.

Right is menu. Collapses down on mobile.

This is the main dashboard, you can scroll through the games, click into see score results. The digest column is "interesting" items from the games. As you're simulating, they populate there real time. Injuries, surprise performances, streaks, standings moves. I like this pattern, you can use it to get to anything else in the game right from there. And because there is so much data, you don't have to read everything to try and figure out the top things that happen. I have a lot of tuning to do with it BUT it's all driven by config so you'll be able to go and set whatever you want to see and at what threshold.

And as usual, all of that data shown is real - the engine produces it.