Say what is known about a world, and how it is known
Four changes to the readout panel and the body cards, which between them were showing less than the catalogues hold and not always distinguishing a measurement from an inference. Picking a planet used to navigate straight to /body/:id. That tore down the system scene and the camera with it, so comparing two planets meant flying back into the system between each. Hovering a body now raises a card over the live view and clicking pins it; Full view still opens the route for the full 3D inspection. Clicking empty space unpins, and leaving the system clears it. The card and the detail page were assembling "what do we know about this world" independently, which is the shape of bug where a planet reads 255 K in one panel and 254 K in the other. Both now build from one shared view model. Orbital period was absent everywhere. For a heliocentric orbit it follows exactly from the semi-major axis, because in these units the Sun's mass is the unit of mass — Mars comes back 687.0 d against a published 686.98. It is deliberately not computed for moons, whose elements are relative to a parent planet the catalogue has no mass for, nor for exoplanets: periodDays is populated for none of the 6319 shipped records and hostStarMassSolar for none either, so any figure would assume a solar-mass host and mis-state every planet around an M dwarf. Where a period does exist it is filed under Measured or Derived according to which it is, not by its field name. The system readout showed a flat 0.00 pc for the Sun's distance, which is arithmetically right and reads as a bug — the distance from here to here is not a measurement, so it is suppressed. It gains the host star's luminosity, marked as derived, and counts moons separately from planets. The neighbourhood readout gains the one thing the star field cannot show: how many of those points can actually be entered. Derived readouts carry a marker and a footnote saying so. Every quantity now formats through one module whose precision follows magnitude, rather than a fixed decimal count per call site that read as false precision at one end and lost real information at the other: 0.0026 AU stays legible instead of rounding to 0.00, and Pluto's period reads 248 yr rather than 90560 d. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Formatting for every physical quantity the HUD and the body cards display.
|
||||
*
|
||||
* Shared rather than per-component so the same measurement reads identically wherever it
|
||||
* appears. The rule throughout is that precision follows magnitude — a figure is shown to the
|
||||
* digits that carry information at its own scale, not to a fixed decimal count that reads as
|
||||
* false precision at one end (`0.00 pc`) and loses real information at the other (`26000 pc`).
|
||||
*/
|
||||
|
||||
/** Distance in parsecs, switching to kiloparsecs where the number would otherwise run long. */
|
||||
export function formatParsecs(distancePc: number): string {
|
||||
return distancePc >= 1000 ? `${(distancePc / 1000).toFixed(1)} kpc` : `${distancePc.toFixed(distancePc < 10 ? 2 : 0)} pc`;
|
||||
}
|
||||
|
||||
/** Distance in astronomical units, for anything inside a system. */
|
||||
export function formatAu(distanceAu: number): string {
|
||||
if (distanceAu < 0.01) {
|
||||
// Close-in exoplanets: 0.0026 AU is a real, published semi-major axis, and two decimals
|
||||
// would round every hot Jupiter in the catalogue to the same `0.00`.
|
||||
return `${distanceAu.toFixed(4)} AU`;
|
||||
}
|
||||
return distanceAu >= 100 ? `${distanceAu.toFixed(0)} AU` : `${distanceAu.toFixed(2)} AU`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Orbital period in whichever unit reads naturally at its length — hours for the very short
|
||||
* periods common among hot Jupiters, days up to a couple of years, then years.
|
||||
*/
|
||||
export function formatPeriod(days: number): string {
|
||||
if (days < 1) {
|
||||
return `${(days * 24).toFixed(1)} h`;
|
||||
}
|
||||
if (days < 700) {
|
||||
return `${days.toFixed(days < 10 ? 2 : 1)} d`;
|
||||
}
|
||||
return `${(days / 365.25).toFixed(days / 365.25 < 100 ? 1 : 0)} yr`;
|
||||
}
|
||||
|
||||
/** Radius in kilometres, or Earth radii once the number stops being legible in km. */
|
||||
export function formatRadiusKm(radiusKm: number): string {
|
||||
return radiusKm >= 10_000 ? `${Math.round(radiusKm).toLocaleString('en-GB')} km` : `${radiusKm.toFixed(radiusKm < 100 ? 1 : 0)} km`;
|
||||
}
|
||||
|
||||
/** Mass in Earth masses. */
|
||||
export function formatMassEarth(massEarth: number): string {
|
||||
if (massEarth >= 100) {
|
||||
return `${massEarth.toFixed(0)} M⊕`;
|
||||
}
|
||||
return `${massEarth.toFixed(massEarth < 1 ? 3 : 2)} M⊕`;
|
||||
}
|
||||
|
||||
/** Equilibrium temperature. Always a whole kelvin — the model is not good to a fraction of one. */
|
||||
export function formatTemperature(kelvin: number): string {
|
||||
return `${Math.round(kelvin)} K`;
|
||||
}
|
||||
|
||||
/** Bulk density. */
|
||||
export function formatDensity(gramsPerCm3: number): string {
|
||||
return `${gramsPerCm3.toFixed(2)} g/cm³`;
|
||||
}
|
||||
|
||||
/** Bolometric luminosity in solar units, which spans many orders of magnitude. */
|
||||
export function formatLuminosity(solar: number): string {
|
||||
if (solar >= 1000 || (solar > 0 && solar < 0.001)) {
|
||||
const exponent = Math.floor(Math.log10(solar));
|
||||
return `${(solar / Math.pow(10, exponent)).toFixed(1)}×10${superscript(exponent)} L☉`;
|
||||
}
|
||||
return `${solar.toFixed(solar < 1 ? 3 : 2)} L☉`;
|
||||
}
|
||||
|
||||
const SUPERSCRIPTS = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
|
||||
|
||||
function superscript(value: number): string {
|
||||
const digits = Math.abs(value)
|
||||
.toString()
|
||||
.split('')
|
||||
.map((digit) => SUPERSCRIPTS[Number(digit)])
|
||||
.join('');
|
||||
return value < 0 ? `⁻${digits}` : digits;
|
||||
}
|
||||
Reference in New Issue
Block a user