Running FloatDB, the largest database of CS:GO skins, is great for traders to find the items they want but also has the ability to allow us to peek into statistics about the distributions of items in the game. This article will look into the relative rarity of paint seeds and float values, float value extremities (rare drops), and how CS:GO skins are generated.
As a small primer, every skin in CS:GO is generated with random attributes when it is opened in a crate or dropped in-game. The main attributes that matter to most traders are the "float value" and "paint seed". The float value determines the opacity of wear that is on the skin, and the paint seed defines random scale, translate, and rotation transformations that are applied to the skin texture.
Float Value Distribution
As stated earlier, float values in CS:GO determine the amount of wear a skin has, and typically ranges from 0-1. The closer to 1, the more worn or "Battle-Scarred" the skin will look. To be a bit more technical, these are IEEE 754 32-bit floats that carry quite a bit of information. If you saw numbers such as 0.07239230 next to a skin, it was likely the float value.
Let's look at how the distribution of float values are for all the AK-47 | Case Hardened skins:
We can see that the distribution is uniform only within a given range of 0.0-0.07, 0.07-0.15, 0.15-0.38, 0.38-0.45, 0.45-1.00. This lines up perfectly with the wear ranges of Factory New, Minimal Wear, Field-Tested, Well-Worn, Battle-Scarred.
If we take the percentage of items in each bucket out of every AK-47 | Case Hardened wear, we get this:
|Factory New (0.00-0.07)||~3%|
|Minimal Wear (0.07-0.15)||~24%|
So if you open a case in CS:GO and it is determined that you will receive a AK-47 | Case Hardened, there is a 3% that it is Factory New.
The Case of the Missing Float Values
You might have noticed above that there is a gap between the buckets in the above graph between each wear range (ex. 0.07-0.08) and chalked it up to some graphical error. But there actually are missing float values from skins that are unboxed from crates!
For example, there are no M4A4 | Magnesium skins with a 0.07-0.08 float on FloatDB because you can't trade up to it and it has a wear range of 0-1. This doesn't apply to skins generated from trade-ups since the formula is different.
Why does this gap exist? Well, maybe Valve wanted to differentiate the difference between wear ranges in a more prominent way, so they introduced a gap to make the next more worn range more noticeably worn, even if it generated a float value that was the best for that range.
Capped Float Ranges
If you're a more experienced trader, you'd know that not all skins have a 0-1 float range. In fact, most of the skins from the original collections in 2014 were generated with a 0.06-0.80 range and it is actually the default in the game files unless the skin creator overrides it. This is typically needed when a 0.06 minimum float would look too worn for a skin, even if it generated the best possible wear.
So what does the float distribution look like if the range isn't 0.0-1.0? Here's an example with the Negev | Loudmouth, a range of 0.14-0.65.
You can see that there's a similar shape to the distribution as the AK-47 | Case Hardened example we saw above, but compressed into the wear range of 0.14-0.65.
What this means is that if your skin doesn't have a wear range from 0-1, two guns spawning that are both Field-Tested do not necessarily have the same probability of float values. In this instance, we can see that getting a Field-Tested skin in 0.18-0.22 is much more probable than a Field-Tested skin in 0.22-0.26.
From this graph it looks like skin generation generates a 0-1 float according to the probability table above, then determines the final value from the calculation:
final_float = float * (max_float - min_float) + min_float
If you'd like to see the wear range for any skin in the game, you can browse them in the CSGOFloat Trade Up Calculator. There are little black marks on the float bar where the min and max range is.
Float Value Extremities
One of the main parts of collecting skins is not just having a lower float value, but having of the lowest or highest float skins in the game.
So how does the distribution of float values look as we go towards the very low end (<0.002)?
As we can see, it still remains uniformly random even when reaching these lower values.
We've personally done a bunch of analysis on how float values in CS:GO are generated, and we actually know the exact randomness generator they use server-side in order to create these values. If you're interested, we've ported their generator into Golang if you feel like testing something out.
Within a given wear range such as 0.15-0.38, the float generator aims to generate the float in a uniform-random way. In other words, any float in that range should be as probable as a another. Generating a 0.0000001 float skin should be as probable as a 0.0330487324 skin if there is a 0-1 wear range.
Paint Seed Distribution
While float value controls how much wear a skin has, the paint seed controls how the texture is placed on the skin. The paint seed ranges from 0-1000 and is used as a "seed" to a random number generator in order to output random transformations to the x, y offset and rotation of the skin and wear textures.
Not all skins are affected by the random displacement of a paint seed, but you've probably noticed that skins such as AK-47 | Case Hardened all look different – this is why. If two AK-47 | Case Hardened skins have the same paint seed, the blue and gold will be in the exact same place across both.
So when CS:GO generates the paint seed for skins, what does the distribution look like?
Given the 50,000 sample size, it is likely fine to assume that it is generated uniformly random across the 0-1000 range. ie. a 456 is as probable as a 964 paint seed.
Fun Fact: A 1000 paint seed is only possible if it originated from a trade-up.
So this shows us that the #1 pattern for an AK-47 | Case Hardened with a paint seed of 661 has a 1/1000 chance of occurring if you unbox an AK-47 | Case Hardened.
Skewed By Trade Ups
Due to how trade ups work, typically they are skewed towards having lower float value outputs since many skins have a max float less than 1. We'll likely have a post in the future diving deeper in the math of trade ups.
Since the community has reverse engineered how float values interact with trade ups, they can more easily be "gamed" to produce an item with lower float. You can play around with this in our Trade Up Calculator.
Here's how it looks like for the AWP | Dragon Lore:
Quest Reward Dragon Lores originated as a drop in the game rather than being traded up to and therefore can't have their float manipulated. As a result, it looks similar to the distributions we saw above (the missing floats aren't as visible due to the x-axis scaling).
It's actually incredible that there is so much depth into how items are generated in CS:GO. These properties have spawned float collectors, incredibly rare skins, and allows the ability for a third-party database to exist.
If you'd like to browse the full database of over 330 million unique items, be sure to check out FloatDB.