feat(atlas): add gravity, orbital period, rotation + sync-wiki command

Schema: added orbital_period_days and rotation_period_hours to bodies
table. Proposal format now includes surface_gravity, orbital_period_days,
rotation_period_hours with sensible defaults per body type.

New sync-wiki command generates a Celestial Bodies section in wiki
pages from DB data. All 16 fields rendered including Year (d) and
Day (h). Re-authored Gateway (GJ 71) with full physics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 18:26:42 +01:00
co-authored by Claude Opus 4.6
parent b77c94a6d8
commit 05c3227b53
4 changed files with 89 additions and 23 deletions
+23 -2
View File
@@ -21,13 +21,16 @@
"inhabited": false,
"population": 0,
"mass_class": "terrestrial",
"surface_gravity": 0.35,
"orbital_period_days": 42,
"rotation_period_hours": 1012,
"atmosphere": "none",
"biome_summary": "barren",
"hydrosphere": "none",
"economic_role": null,
"settlement_pattern": null,
"industrial_corridor": null,
"notes": "inner rocky"
"notes": "inner rocky, tidally locked"
},
{
"body_id": "GJ71c",
@@ -38,6 +41,9 @@
"inhabited": true,
"population": 600000000,
"mass_class": "terrestrial",
"surface_gravity": 0.92,
"orbital_period_days": 310,
"rotation_period_hours": 22.4,
"atmosphere": "breathable",
"biome_summary": "temperate",
"hydrosphere": "ocean",
@@ -55,6 +61,9 @@
"inhabited": true,
"population": 500000000,
"mass_class": "terrestrial",
"surface_gravity": 0.87,
"orbital_period_days": 520,
"rotation_period_hours": 27.1,
"atmosphere": "breathable",
"biome_summary": "temperate",
"hydrosphere": "rivers",
@@ -72,13 +81,16 @@
"inhabited": true,
"population": 20000000,
"mass_class": "dwarf",
"surface_gravity": 0.12,
"orbital_period_days": 8.2,
"rotation_period_hours": 196.8,
"atmosphere": "none",
"biome_summary": "barren",
"hydrosphere": "none",
"economic_role": "transit",
"settlement_pattern": "domed",
"industrial_corridor": null,
"notes": "domed service settlement"
"notes": "domed service settlement, tidally locked to Arden"
},
{
"body_id": "GJ71e",
@@ -89,6 +101,9 @@
"inhabited": false,
"population": 0,
"mass_class": "terrestrial",
"surface_gravity": 0.45,
"orbital_period_days": 1850,
"rotation_period_hours": 16.3,
"atmosphere": "thin",
"biome_summary": "frozen",
"hydrosphere": "ice",
@@ -106,6 +121,9 @@
"inhabited": false,
"population": 0,
"mass_class": null,
"surface_gravity": null,
"orbital_period_days": null,
"rotation_period_hours": null,
"atmosphere": null,
"biome_summary": null,
"hydrosphere": null,
@@ -123,6 +141,9 @@
"inhabited": false,
"population": 0,
"mass_class": null,
"surface_gravity": null,
"orbital_period_days": null,
"rotation_period_hours": null,
"atmosphere": null,
"biome_summary": null,
"hydrosphere": null,
+2
View File
@@ -142,6 +142,8 @@ CREATE TABLE IF NOT EXISTS bodies (
mass_class TEXT, -- terrestrial, super_earth, ice_giant, gas_giant, dwarf
atmosphere TEXT, -- breathable, thin, toxic, none, dense
surface_gravity REAL, -- in g (Earth = 1.0), NULL for gas giants
orbital_period_days REAL, -- orbital period in Earth days, NULL for oort/belt
rotation_period_hours REAL, -- rotation period in Earth hours (Earth = 24), NULL for tidally locked/gas giants
biome_summary TEXT, -- temperate, arid, frozen, oceanic, volcanic, barren, mixed
hydrosphere TEXT, -- ocean, ice, rivers, none, subsurface
+55 -11
View File
@@ -236,6 +236,9 @@ struct ProposalBody {
inhabited: bool,
population: Option<i64>,
mass_class: Option<String>,
surface_gravity: Option<f64>,
orbital_period_days: Option<f64>,
rotation_period_hours: Option<f64>,
atmosphere: Option<String>,
biome_summary: Option<String>,
hydrosphere: Option<String>,
@@ -806,6 +809,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("terrestrial".into()),
surface_gravity: Some(0.38),
orbital_period_days: Some(88.0),
rotation_period_hours: Some(1408.0),
atmosphere: Some("none".into()),
biome_summary: Some("barren".into()),
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -831,6 +837,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("terrestrial".into()),
surface_gravity: Some(0.9),
orbital_period_days: Some(365.0),
rotation_period_hours: Some(24.0),
atmosphere: Some("breathable".into()),
biome_summary: Some("temperate".into()),
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -857,6 +866,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("terrestrial".into()),
surface_gravity: Some(0.85),
orbital_period_days: Some(400.0),
rotation_period_hours: Some(26.0),
atmosphere: Some("breathable".into()),
biome_summary: Some("temperate".into()),
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -884,6 +896,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("terrestrial".into()),
surface_gravity: Some(0.5),
orbital_period_days: Some(2000.0),
rotation_period_hours: Some(18.0),
atmosphere: Some("thin".into()),
biome_summary: Some("frozen".into()),
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -903,6 +918,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: None,
surface_gravity: None,
orbital_period_days: None,
rotation_period_hours: None,
atmosphere: None,
biome_summary: None,
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -928,6 +946,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("gas_giant".into()),
surface_gravity: None,
orbital_period_days: Some(4300.0),
rotation_period_hours: Some(10.0),
atmosphere: Some("dense".into()),
biome_summary: None,
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -944,6 +965,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: Some("dwarf".into()),
surface_gravity: Some(0.1),
orbital_period_days: Some(3.5 * m as f64),
rotation_period_hours: Some(3.5 * 24.0 * m as f64),
atmosphere: Some("none".into()),
biome_summary: Some("barren".into()),
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -964,6 +988,9 @@ fn generate_body_matrix(
proper_name: None,
population: None,
mass_class: None,
surface_gravity: None,
orbital_period_days: None,
rotation_period_hours: None,
atmosphere: None,
biome_summary: None,
hydrosphere: None, economic_role: None, settlement_pattern: None, industrial_corridor: None,
@@ -1104,10 +1131,11 @@ fn cmd_commit_system(conn: &Connection, path: &str) {
for body in &proposal.bodies {
tx.execute(
"INSERT INTO bodies (body_id, system_id, parent_body_id, body_type, orbit_index,
proper_name, inhabited, population, mass_class, atmosphere,
proper_name, inhabited, population, mass_class, surface_gravity,
orbital_period_days, rotation_period_hours, atmosphere,
biome_summary, hydrosphere, economic_role, settlement_pattern,
industrial_corridor)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)",
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18)",
params![
body.body_id,
proposal.system_id,
@@ -1118,6 +1146,9 @@ fn cmd_commit_system(conn: &Connection, path: &str) {
body.inhabited as i32,
body.population.unwrap_or(0),
body.mass_class,
body.surface_gravity,
body.orbital_period_days,
body.rotation_period_hours,
body.atmosphere,
body.biome_summary,
body.hydrosphere,
@@ -1270,6 +1301,7 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
.prepare(
"SELECT body_id, proper_name, body_type, orbit_index, parent_body_id,
inhabited, population, mass_class, atmosphere, surface_gravity,
orbital_period_days, rotation_period_hours,
biome_summary, hydrosphere, economic_role, settlement_pattern,
industrial_corridor
FROM bodies WHERE system_id = ?1
@@ -1288,6 +1320,8 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
mass_class: Option<String>,
atmosphere: Option<String>,
gravity: Option<f64>,
orbital_days: Option<f64>,
rotation_hours: Option<f64>,
biome: Option<String>,
hydro: Option<String>,
econ: Option<String>,
@@ -1308,11 +1342,13 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
mass_class: row.get(7)?,
atmosphere: row.get(8)?,
gravity: row.get(9)?,
biome: row.get(10)?,
hydro: row.get(11)?,
econ: row.get(12)?,
settlement: row.get(13)?,
industrial: row.get(14)?,
orbital_days: row.get(10)?,
rotation_hours: row.get(11)?,
biome: row.get(12)?,
hydro: row.get(13)?,
econ: row.get(14)?,
settlement: row.get(15)?,
industrial: row.get(16)?,
})
})
.unwrap()
@@ -1373,8 +1409,8 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
// Bodies table
if !bodies.is_empty() {
section.push_str("| Orbit | ID | Name | Type | Inhabited | Population | Mass | Gravity | Atmosphere | Biome | Hydrosphere | Economy | Settlement | Industrial |\n");
section.push_str("|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n");
section.push_str("| Orbit | ID | Name | Type | Inhabited | Pop | Mass | Gravity | Year (d) | Day (h) | Atmo | Biome | Hydro | Economy | Settlement | Industrial |\n");
section.push_str("|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n");
// First pass: top-level bodies (no parent)
for b in &bodies {
@@ -1388,8 +1424,10 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
"".to_string()
};
let grav = b.gravity.map(|g| format!("{:.2}g", g)).unwrap_or_else(|| "".to_string());
let year = b.orbital_days.map(|d| format!("{:.0}", d)).unwrap_or_else(|| "".to_string());
let day = b.rotation_hours.map(|h| format!("{:.1}", h)).unwrap_or_else(|| "".to_string());
section.push_str(&format!(
"| {} | `{}` | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
"| {} | `{}` | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
b.orbit,
b.id,
name,
@@ -1398,6 +1436,8 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
pop,
b.mass_class.as_deref().unwrap_or(""),
grav,
year,
day,
b.atmosphere.as_deref().unwrap_or(""),
b.biome.as_deref().unwrap_or(""),
b.hydro.as_deref().unwrap_or(""),
@@ -1416,8 +1456,10 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
"".to_string()
};
let mgrav = m.gravity.map(|g| format!("{:.2}g", g)).unwrap_or_else(|| "".to_string());
let myear = m.orbital_days.map(|d| format!("{:.0}", d)).unwrap_or_else(|| "".to_string());
let mday = m.rotation_hours.map(|h| format!("{:.1}", h)).unwrap_or_else(|| "".to_string());
section.push_str(&format!(
"| ↳ {}.{} | `{}` | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
"| ↳ {}.{} | `{}` | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
b.orbit,
m.orbit,
m.id,
@@ -1427,6 +1469,8 @@ fn cmd_sync_wiki(conn: &Connection, system_id: Option<&str>, wiki_dir: &str) {
mpop,
m.mass_class.as_deref().unwrap_or(""),
mgrav,
myear,
mday,
m.atmosphere.as_deref().unwrap_or(""),
m.biome.as_deref().unwrap_or(""),
m.hydro.as_deref().unwrap_or(""),
+9 -10
View File
@@ -70,19 +70,18 @@ The Institute has been studying the first horizon station for five hundred years
## Celestial Bodies
<!-- READ-ONLY — generated from systems.db bodies/stations tables -->
| Orbit | ID | Name | Type | Inhabited | Population | Mass | Gravity | Atmosphere | Biome | Hydrosphere | Economy | Settlement | Industrial |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | `GJ71b` | — | planet | no | — | terrestrial | | none | barren | none | — | — | — |
| 2 | `GJ71c` | Threshold | planet | yes | 600M | terrestrial | | breathable | temperate | ocean | agricultural | urban_concentrated | — |
| 3 | `GJ71d` | Arden | planet | yes | 500M | terrestrial | | breathable | temperate | rivers | agricultural | dispersed_rural | — |
| ↳ 3.1 | `GJ71d-1` | Verantis | moon | yes | 20M | dwarf | | none | barren | none | transit | domed | — |
| 4 | `GJ71e` | — | planet | no | — | terrestrial | | thin | frozen | ice | — | — | — |
| 5 | `GJ71-belt` | — | asteroid_belt | no | — | — | — | — | — | — | — | — | — |
| 6 | `GJ71-oort` | — | oort_cloud | no | — | — | — | — | — | — | — | — | — |
| Orbit | ID | Name | Type | Inhabited | Pop | Mass | Gravity | Year (d) | Day (h) | Atmo | Biome | Hydro | Economy | Settlement | Industrial |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | `GJ71b` | — | planet | no | — | terrestrial | 0.35g | 42 | 1012.0 | none | barren | none | — | — | — |
| 2 | `GJ71c` | Threshold | planet | yes | 600M | terrestrial | 0.92g | 310 | 22.4 | breathable | temperate | ocean | agricultural | urban_concentrated | — |
| 3 | `GJ71d` | Arden | planet | yes | 500M | terrestrial | 0.87g | 520 | 27.1 | breathable | temperate | rivers | agricultural | dispersed_rural | — |
| ↳ 3.1 | `GJ71d-1` | Verantis | moon | yes | 20M | dwarf | 0.12g | 8 | 196.8 | none | barren | none | transit | domed | — |
| 4 | `GJ71e` | — | planet | no | — | terrestrial | 0.45g | 1850 | 16.3 | thin | frozen | ice | — | — | — |
| 5 | `GJ71-belt` | — | asteroid_belt | no | — | — | — | — | — | — | — | — | — | — | — |
| 6 | `GJ71-oort` | — | oort_cloud | no | — | — | — | — | — | — | — | — | — | — | — |
### Stations & Facilities
| ID | Name | Type | Orbits | Population | Economy | Governance | Docking | Gate | Districts |
|---|---|---|---|---|---|---|---|---|---|
| `GJ71-oort-S1` | Horizon Station | horizon | `GJ71-oort` | 80M | transit | — | major | yes | 1 |