Give the home world a real name from the bank, and show object names on the compass

Two small naming/labeling fixes:

1. The home planet was always the generic "Terra". It now takes the first
   name off the STARTING system's planet-name deck (SystemGenerator), so it
   reads as a real place and can never clash with one of that system's
   planets. Stored as content.homeName (only the starting system has one);
   the old planets.homeName stays as a fallback. Used for the compass
   home chip and the tether anchor label.

2. Confirmed/sharpened the compass name tag: each discovered off-screen
   object's arrow chip already renders TYPE + NAME — now the home world
   shows its bank name too (e.g. "HOME WORLD · ESHKAELURA").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Brian Fertig 2026-09-03 22:41:06 -06:00
parent d355fd50e4
commit a1db1cc672
5 changed files with 41 additions and 10 deletions

View File

@ -52,12 +52,15 @@ python3 -m http.server 8080
- Game screen with a top-down ship (real spritesheet art — frame 0 of - Game screen with a top-down ship (real spritesheet art — frame 0 of
`assets/images/ships-player.png`, see `data/ship.json`): **click anywhere to fly there** `assets/images/ships-player.png`, see `data/ship.json`): **click anywhere to fly there**
in the current system's open space (system boundaries/jumps come next). in the current system's open space (system boundaries/jumps come next).
Discovered worlds get a screen-edge arrow + name tag; **clicking the Discovered worlds get a screen-edge arrow + a name tag showing the
world's **name** (e.g. `HOME WORLD · ESHKAELURA`); **clicking the
name tag autopilots the ship there** (it arrives on the keep-out rim, name tag autopilots the ship there** (it arrives on the keep-out rim,
facing the world) facing the world)
- **The home planet** — the player's Terran world — in the system you - **The home planet** — the player's world — in the system you start in:
start in: a 1024 px disc rendered 1:1 from the `assets/images/planets.png` a 1024 px disc rendered 1:1 from the `assets/images/planets.png`
spritesheet. Which Terran face it shows (frames 02) is a spritesheet, with a **proper name drawn from the planet name bank** (the
first name off the starting system's deck, so it never clashes with one
of the other worlds). Which Terran face it shows (frames 02) is a
seed-deterministic pick, so the same galaxy always yields the same home seed-deterministic pick, so the same galaxy always yields the same home
world. The ship spawns ~150 px (edge-to-edge) off its rim in a world. The ship spawns ~150 px (edge-to-edge) off its rim in a
seed-derived direction, may fly in as close as 50 px from the rim, and seed-derived direction, may fly in as close as 50 px from the rim, and

View File

@ -326,6 +326,18 @@ let big;
}); });
check('within a system: planet names & station names are all distinct', noDupOk); check('within a system: planet names & station names are all distinct', noDupOk);
// The starting system's HOME world gets a bank name distinct from its
// planets; only the starting system has one.
const homeRec = big2.currentSystem();
const homeC = big2.ensureContent(homeRec.id);
check(
'starting system has a home-world bank name, distinct from its planets',
typeof homeC.homeName === 'string' && homeC.homeName.length > 0 &&
!homeC.planets.some((p) => p.name === homeC.homeName),
);
const nonHomeRec = big2.records.find((r) => r.id !== homeRec.id);
check('other systems have no home world', !('homeName' in big2.ensureContent(nonHomeRec.id)));
// Lazy === eager still holds with the lived-in layer (spot check). // Lazy === eager still holds with the lived-in layer (spot check).
const fresh2 = Galaxy.create(SEED); const fresh2 = Galaxy.create(SEED);
check('settlements: lazy content === content from a fresh galaxy', deepEq(fresh2.ensureContent(big2.records[0].id).settlements, big2.ensureContent(big2.records[0].id).settlements)); check('settlements: lazy content === content from a fresh galaxy', deepEq(fresh2.ensureContent(big2.records[0].id).settlements, big2.ensureContent(big2.records[0].id).settlements));

View File

@ -160,8 +160,11 @@ unclaimed". Model & seams:
more bodies than the bank holds (impossible at these sizes). The decks are more bodies than the bank holds (impossible at these sizes). The decks are
dealt from dedicated derived streams (`Rng.derive(seed,'system',id,'names', dealt from dedicated derived streams (`Rng.derive(seed,'system',id,'names',
'planets'|'stations')`) so they stay order-independent (lazy === eager). 'planets'|'stations')`) so they stay order-independent (lazy === eager).
The home world keeps its configured name (`planets.homeName`), and stars / The **home world** (the player's planet, in the starting system only) takes
the galaxy are still synthesised from syllable pools (unbounded). the first name off that system's planet deck — so it gets a real bank name
too, never clashing with one of the planets (`content.homeName`; the old
`planets.homeName` is now just a fallback). Stars and the galaxy are still
synthesised from syllable pools (unbounded).
## The current system is a place, not just a dossier (discovery + compass) ## The current system is a place, not just a dossier (discovery + compass)

View File

@ -68,6 +68,12 @@ export function generateSystemContent(galaxy, record, typeDefs = null) {
const planetDeck = NameGenerator.planetDeck( const planetDeck = NameGenerator.planetDeck(
Rng.derive(galaxy.seed, 'system', record.id, 'names', 'planets') Rng.derive(galaxy.seed, 'system', record.id, 'names', 'planets')
); );
// The player's home world sits at the origin of the STARTING system and is
// not one of the generated planets. It takes the first name off that
// system's deck so it can never clash with a planet; the planets then draw
// from the rest of the deck (all distinct within the system).
const isHome = record.id === galaxy?.currentSystemId;
const homeName = isHome ? planetDeck[0] : null;
const planets = []; const planets = [];
for (let i = 1; i <= count; i++) { for (let i = 1; i <= count; i++) {
const pclass = rng.weighted(classWeights, 'rocky'); const pclass = rng.weighted(classWeights, 'rocky');
@ -77,7 +83,7 @@ export function generateSystemContent(galaxy, record, typeDefs = null) {
moons = pclass === 'gas' || pclass === 'ice' ? rng.int(1, 6) : rng.int(0, 2); moons = pclass === 'gas' || pclass === 'ice' ? rng.int(1, 6) : rng.int(0, 2);
} }
planets.push({ planets.push({
name: planetDeck[(i - 1) % planetDeck.length], name: planetDeck[(isHome ? i : i - 1) % planetDeck.length],
ordinal: i, ordinal: i,
class: pclass, class: pclass,
moons, moons,
@ -105,7 +111,7 @@ export function generateSystemContent(galaxy, record, typeDefs = null) {
}; };
const hazard = rng.chance(attr.hazard ?? 0.1); const hazard = rng.chance(attr.hazard ?? 0.1);
return { const content = {
name: record.name, name: record.name,
type: record.type, type: record.type,
star, star,
@ -114,6 +120,8 @@ export function generateSystemContent(galaxy, record, typeDefs = null) {
belt, belt,
hazard, hazard,
}; };
if (isHome) content.homeName = homeName; // the player's home world (starting system only)
return content;
} }
/** /**

View File

@ -83,6 +83,11 @@ export class GameScene extends Phaser.Scene {
this.ensureGalaxy(); this.ensureGalaxy();
this.systemRecord = this.galaxy.currentSystem(); this.systemRecord = this.galaxy.currentSystem();
this.systemContent = this.galaxy.ensureContent(this.systemRecord.id); this.systemContent = this.galaxy.ensureContent(this.systemRecord.id);
// The home world's name — dealt from the planet name bank by the
// generator (the starting system is the only one with a home world), so
// it reads as a real place rather than a generic "Terra". Fallback keeps
// the old configured name if the bank is ever unavailable.
this.homeWorldName = this.systemContent.homeName || config.get('planets.homeName', 'Terra');
this.createSystemHud(); this.createSystemHud();
// The home planet — the player's Terran world, always present in the // The home planet — the player's Terran world, always present in the
@ -158,7 +163,7 @@ export class GameScene extends Phaser.Scene {
config.get('tether.homeId', 'home'), config.get('tether.homeId', 'home'),
0, 0, // home world's center (it sits at the system origin) 0, 0, // home world's center (it sits at the system origin)
config.get('tether.homeLevel', 1), config.get('tether.homeLevel', 1),
config.get('tether.homeLabel', '') || config.get('planets.homeName', 'Terra'), config.get('tether.homeLabel', '') || this.homeWorldName,
); );
this.tetherToastAt = null; this.tetherToastAt = null;
this.refreshTetherHud(); this.refreshTetherHud();
@ -468,7 +473,7 @@ export class GameScene extends Phaser.Scene {
y: this.planet.y, y: this.planet.y,
radius: this.planet.radius, radius: this.planet.radius,
typeLabel: config.get('planets.homeTypeLabel', 'Home World'), typeLabel: config.get('planets.homeTypeLabel', 'Home World'),
name: config.get('planets.homeName', 'Terra'), name: this.homeWorldName,
}); });
for (const p of this.systemPlanets) { for (const p of this.systemPlanets) {
out.push({ out.push({