Using data from the Kepler mission to scientifically imagine star systems

I recently got the procgen bug and the space nerd bug at the same time. So I decided to see if I could write a bit of code that could generate star systems that pass the astronomy nerd sniff test based on recent research.

I'm sure I made a lot of mistakes, and if this is ever posted in a proper space science forum many flaws will be found, but even so, I think I fulfilled the spirit of my mission.

I'm not really an astronomy nerd myself, so I started with Wikipedia pages. I learned about the Kepler mission. I found some charming old-school web sites. All told, I skimmed about 40 articles and papers, and directly used about half of what I came across.

When I finished, I published a JavaScript library called Stellar Dream that programmers can use in their own projects. I also built a cute Windows 95-style web app that lets you browse imaginary star systems as if you were using digital telescope software: The Keplverse! My hope is that people will use this tool to assist in worldbuilding for roleplaying campaigns and works of art.

Play with the imaginary telescope

Keplverse Telescope Software 1.0.png


The first thing you need in a star system is a star. I decided to include only main sequence stars, since some of my sources didn't include information about anything else. Non-main-sequence stars, i.e. giants and white dwarfs, happen to be inhospitable to interesting exoplanets anyway.

Star type is picked using a simple weighted random choice. Each star type is associated with an approximate color, luminosity range, and radius range. The mass can be computed from luminosity.

Colors are from What color are the stars? by Mitchell Charity. Probabilities are from The Real Starry Sky by Glenn LeDrew.

Type Probability Color
M 0.7645629 #9bb0ff
K 0.1213592 #aabfff
G 0.0764563 #cad7ff
F 0.0303398 #f8f7ff
A 0.0060679 #fff4ea
B 0.0012136 #ffd2a1
O 0.0000003 #ffcc6f

Radius, temperature, and luminosity are much trickier. Calculating the Radius of a Star from the Sloan Digital Sky Survey explains how to do it properly, but I hate real math, so I just took a random value 0-1 and mapped it to a min and max value for the star based on its type. Because I was much more interested in planets than stars, and I wasn't planning to create accurate orbital mechanics, I was eager to hand-wave past this part of the generator.

Every star system has a habitable zone: an orbital radius that is close enough for liquid water to exist on a planet's surface, but far enough away for the atmosphere not to burn off. I learned how to compute the habitable zone for each type of star from, an amazing Web 1.0 site. You combine the star's luminosity with a magic (to me) number, the normalized solar flux factor, or seff. Each star has a seffMin and seffMax value representing the beginning and end of the habitable zone. The habitable zone boundaries in AU can be computed using Math.sqrt(luminosity / seff[Min|Max]).

The last interesting value I chose to look at was metallicity. Research published in The Astrophysics Journal in 2004 by Fischer and Valenti suggests that gas giants are much more common around stars with high metallicity. My best approximation for picking reasonable metallicity values came from a small figure on page 5 of The Metallicity Distribution of the Milky Way Bulge by Ness and Freeman. I combined two Gaussian distributions that put most stars in the 0–0.5 range, with the rest at -0.5–0. There's a correlation between high metallicity and proximity to the galactic plane, but I explicitly ignored that since I wasn't trying to place any stars in a coordinate space.

Binary star systems

Many star systems, perhaps most, contain two or more stars in orbit 0–1 light years apart. The fraction of star systems in various configurations is not well known as far as I could tell. I also didn't want to deal with modeling the effects of the distance between binary stars on orbits and such.

So I decided to do pull some heuristics out of thin air: 11% of the time, an extra star will be added to the system as a “close binary”, and the less massive star will be ignored for planet-generating purposes. The less massive star also does not affect the habitable zone of the system, which I realize might be too extreme of a simplification.


Research on stars has been steady for as long as people have had telescopes, but research on exoplanets took a huge leap forward when NASA launched the Kepler telescope into space, surveying 150,000 stars for exoplanets over four years. Because of this mission, there's a huge difference in the quality and results of research published before and after about the year 2010. I wanted to combine some high-level basic facts from the Kepler mission into a simplistic yet believable model for placing planets in star systems.

What we know about exoplanets

Googling around for Kepler findings is a good way to spend an afternoon. I learned a few interesting and surprising facts, not all directly related to Kepler: * Few gas giants have been found in far-out orbits, despite Jupiter and Saturn being quite far out in our solar system. * At least one in six stars has an earth-like planet. * Planets tend to have a similar size to those in adjacent orbits. (Many Worlds is a great blog!) * Nearly all sun-like stars have earth-like planets. * 70% of stars, regardless of type, have an Earth- or Neptune-like in orbits up to a bit over 1 AU. * M-Dwarf stars have an average of 0.5 Earth-like planets in their habitable zones.

Beyond those neat little nuggets, I also discovered a fun mini-controversy: experts disagree about how to classify planets! Some charts have as many as 8 classes: Mars-size, Earth-size, super-Earth-size, Neptune-size, sub-Jupiter-size, Jupiter-size, and super-Jupiter-size. But an article called Sorry, Super-Earth Fans, There Are Only Three Classes Of Planet, a summary of the much drier Probabilistic Forecasting of the Masses and Radii of Other Worlds, convinced me that there three types is enough:

  1. Terran worlds with rocky surfaces and maybe atmospheres
  2. Neptunian worlds with large atmospheres made of hydrogen and helium
  3. Jovian worlds that are big enough to compress on the inside

The only thing that differentiates these classes is size. Once a planet gains a certain mass, two Earths or so, it gains a hydrogen-helium envelope that is inhospitable to life and becomes a Neptunian planet. And when it crosses another mass threshold, the extreme gravity means it can't have a well-defined surface, and becomes a Jovian. Finally, a body might be massive enough to behave like a successful or failed star, no longer even classified as a planet.

Each planet type has a different mass-radius relation. The unit M⊕ is Earth-masses.

Type Mass (10^X M⊕) Radius exponent (M⊕^x)
Terran -1.3–0.22 0.28
Neptunian 0.22–2 0.59
Jovian 2–3.5 -0.4

Imagining solar systems

Putting all these facts together, I made what I thought was a reasonable pass at a set of simplistic rules.

First, if the star type is A, B, or O, then create no planets. These stars either change too quickly to support life, or have stranger rules regarding planet formation. O-type stars become supernovas, B-type stars may only have gas giants, and I couldn't find enough data on A-type stars. (Terraforming Wiki: Stars and other hosting celestial bodies)

Next, there's a 30% chance of stopping, because only about 70% of remaining star systems have planets at all.

Now that it's time to make some planets, use the some eyeballed and estimated figures to weight different kinds of planets.

I decided to ignore the “planets in adjacent orbits have similar sizes” correlation, and instead pick planet type by simple weighted random choice. But where in orbit will they go? I couldn't find any accessible research-supported models for this, so I pieced together a few ideas:

Combining those ideas, I thought it would be reasonable to create eleven “slots”: one somewhere in the habitable zone, five closer to the star, and five farther away from the star. One would be randomly chosen as the “start,” and then planets could be added inside and outside the existing planets based on some probability, occasionally skipping an orbit just for fun.

I added a special cheat case to match the statistic that M-dwarfs average 0.5 Terran planets in their habitable zones. If the star is an M-dwarf, there's a 40% chance of forcing the start of the planet sequence to be a Terran planet in the habitable zone.

Once a planet is added, there's a 30% chance of adding an additional planet in an orbit closer or farther away from the star. Half the time, an orbit slot is skipped. The 30% value comes from a NASA infographic, Planetary Systems by Number of Known Planets.

Each planet gets a random mass based on its type, and its radius can be computed from its mass.

That's the end of the algorithm! The result is a model of a star system that sort of, kind of, if you squint at it, vaguely lines up with what scientists know about the distribution of exoplanets among star systems.

Future work

There are a few facts I didn't account for in my program that would be simple to fix. I made no attempt to make planets in adjacent orbits have similar sizes, since I couldn't find precise explanations of how strong that correlation was. I also didn't try to build a model of planets any deeper than Kepler studies: I have no idea what planets are made of, or anything about moons around exoplanets. I didn't include asteroid belts, even though they are likely quite common according to /r/cosmology.

Since this program is mainly for science fiction worldbuilding, I think the lack of an orbital period calculator is my biggest missing feature. It's probably a simple calculation, but I haven't yet found a good resource for someone as lazy with math as I am. Hopefully someone taking a physics class can help me out with applying Kepler's 3rd Law. I made an attempt, but I got stuck on dealing with units and the Gaussian gravitational constant.

If you have a suggestion or notice a problem, please email me or open a GitHub issue on either the Stellar Dream or Keplverse project.




Prior art