Public
Edited
Mar 9
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
planets
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
stars
X
mass
Y
temperature
Color
satelliteCount
Size
Facet X
Facet Y
Mark
dot
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
planets
X
orbitTilt
Y
distance
Color
mass
Size
Facet X
Facet Y
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
getSystem(0, 2)
Insert cell
function getSystem(galaxyId, starId) {
const star = starsById[["galaxy", galaxyId, "star", starId]];
const planets = planetsByStar[star.seed];

return {
star,
planets,

planetCount: star.satelliteCount,
mass: _.sum([star.mass, ..._.map(planets, "mass")]),
volume: _.sum([star.volume, ..._.map(planets, "volume")]),
radius: _.max(_.map(planets, "distance"))
};
}
Insert cell
stats = {
const s = {
galaxyCount: galaxies.length,
starCount: stars.length,
planetCount: planets.length,
moonCount: moons.length
};

return {
...s,
objectCount:
s.galaxyCount + s.starCount + s.planetCount + s.moonCount
};
}
Insert cell
Insert cell
Insert cell
galaxies = _.range(settings.galaxyCount).map(id => generateGalaxy({ id }))
Insert cell
stars = generateObjects(galaxies, generateStar)
Insert cell
planets = generateObjects(stars, generatePlanet)
Insert cell
moons = generateObjects(planets, generateMoon)
Insert cell
Insert cell
galaxiesById = _.keyBy(galaxies, 'seed')
Insert cell
starsById = _.keyBy(stars, 'seed')
Insert cell
planetsById = _.keyBy(planets, 'seed')
Insert cell
moonsById = _.keyBy(moons, 'seed')
Insert cell
Insert cell
starsByGalaxy = _.groupBy(stars, 'parentSeed')
Insert cell
planetsByStar = _.groupBy(planets, 'parentSeed')
Insert cell
moonsByPlanet = _.groupBy(moons, 'parentSeed')
Insert cell
Insert cell
Insert cell
function generateObjects (parentList, generator) {
const objects = [];

parentList.forEach((parent, i) => {
parent.satelliteOrbits.forEach(({ distance, orbitTilt }, j) => {
objects.push(
generator({
parent,
id: j,
distance,
orbitTilt
})
);
});
});

return objects;
}
Insert cell
Insert cell
Insert cell
function generateGalaxy({ id }) {
const type = "galaxy";
const seed = [type, id || 0];

const satelliteCount = getSeededInt(
seed,
settings[type].satelliteCountRange[0],
settings[type].satelliteCountRange[1]
);

const satelliteOrbits = generateSatelliteOrbits(seed, type, satelliteCount);

return {
seed,
satelliteCount,
satelliteOrbits
};
}
Insert cell
function generateStar({ parent, id, distance, orbitTilt }) {
const star = enhanceOrbitalObject(
generateOrbitalObject({
parent,
type: "star",
id,
distance,
orbitTilt
})
);

const luminosity = getSeededFloat(
star.seed,
settings[star.type].minLuminosity,
settings[star.type].maxLuminosity
);

// TODO: calculate from mass and luminosity
const lifeTime = 3 * mega;

return {
...star,
lifeTime,
luminosity
};
}
Insert cell
function generatePlanet({ parent, id, distance, orbitTilt }) {
const planet = enhanceOrbitalObject(
generateOrbitalObject({
parent,
type: "planet",
id,
distance,
orbitTilt
})
);

// TODO: calculate luminosity of planet based on the star
const luminosity = parent.luminosity / 1000;

// TODO: enforce size limits based on star
return {
...planet,
luminosity
};
}
Insert cell
function generateMoon({ parent, id, distance, orbitTilt }) {
// TODO: enforce size limits based on planet
const moon = enhanceOrbitalObject(
generateOrbitalObject({
parent,
type: "moon",
id,
distance,
orbitTilt
})
);

return _.omit(moon, ['satelliteOrbits', 'satelliteCount']);
}
Insert cell
Insert cell
Insert cell
function enhanceOrbitalObject(data) {
const circumference = getCircumference(data.radius);
const volume = data.radius ? getVolume(data.radius) : 0;
const mass = data.solarMass ? solarMassInKg(data.solarMass) : 0;
const density = mass && volume ? getDensity(mass, volume) : 0;

return {
...data,
circumference,
mass,
volume,
density
};
}
Insert cell
function generateOrbitalObject({ parent, type, id, distance, orbitTilt }) {
const seed = [...parent.seed, type, id];
const name = generateName(seed, type);

let satelliteCount = 0;
if (settings[type].satelliteCountRange[1]) {
satelliteCount = getSeededInt(
[...seed, "satelliteCount"],
settings[type].satelliteCountRange[0],
settings[type].satelliteCountRange[1]
);
}

let radius = undefined;
if (settings[type].radiusRange) {
radius = getSeededFloat(
[...seed, "radius"],
settings[type].radiusRange[0],
settings[type].radiusRange[1]
);
}

const solarMass = getSeededFloat(
[...seed, "solarMass"],
settings[type].solarMassRange[0],
settings[type].solarMassRange[1]
);

let temperature = undefined;
if (settings[type].temperatureRange) {
temperature = getSeededFloat(
[...seed, "temperature"],
settings[type].temperatureRange[0],
settings[type].temperatureRange[1]
);
}

const satelliteOrbits =
settings[type].satelliteCountRange[1] > 0
? generateSatelliteOrbits(seed, type, satelliteCount)
: undefined;

return {
parentSeed: parent.seed || [],
parentId: parent.seed[parent.seed.length - 1],

seed,
type,
id,
distance,
orbitTilt,

name,
solarMass,
radius,
temperature,

satelliteCount,
satelliteOrbits
};
}
Insert cell
function generateSatelliteOrbits(seed, type, satelliteCount) {
if (satelliteCount) {
const satelliteDistances = getSeededFloats(
satelliteCount,
[...seed, "orbit", "distance"],
settings[type].satelliteDistanceRange[0],
settings[type].satelliteDistanceRange[1]
);
const orbitTilts = getSeededFloats(
satelliteCount,
[...seed, "orbit", "tilt"],
settings[type].satelliteTiltRange[0],
settings[type].satelliteTiltRange[1]
);

return satelliteDistances.map((distance, i) => {
return {
distance,
orbitTilt: orbitTilts[i]
};
});
}

return [];
}
Insert cell
Insert cell
Insert cell
function generateName(seed, type) {
const nameSeed = [...seed, "name"];
const nameSyllableCount = getSeededInt(
nameSeed,
settings[type].nameSyllableRange[0],
settings[type].nameSyllableRange[1]
);

let nameSyllables = [];
for (let i = 0; i < nameSyllableCount; i++) {
nameSyllables.push(
syllables[getSeededInt([...nameSeed, i], 0, syllables.length - 1)]
);
}

// TODO: variation for syllable separation
let name = nameSyllables[0];
for (let i = 1; i < nameSyllables.length; ++i) {
const n = getSeededFloat([...nameSeed, i]);
if (n < 0.1) {
name += "-";
} else if (n > 0.7) {
name += " ";
}
name += nameSyllables[i];
}

return _.capitalize(name);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
solarMassInKg(20)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
solveMassDensityVolume({
density: 10,
mass: 1000
})
Insert cell
solveMassDensityVolume({
density: 10,
volume: 1000
})
Insert cell
solveMassDensityVolume({
mass: 10,
volume: 1000
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
solveRadiusVolume({ radius: 10 })
Insert cell
solveRadiusVolume({ volume: 10 })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
solveRadiusCircumference({ radius: 8 })
Insert cell
solveRadiusCircumference({ circumference: 8 })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more