feat(assets): procedural planet renders for wiki/GTTR — #779

7 planet type PNGs (512×512px RGBA) covering all biome_summary values:
temperate, temperate_terminator, oceanic, arid, frozen, volcanic, barren.

Pure Python ray-sphere renderer (spikes/planet-renders/generate_planets.py)
— numpy/PIL only, no Godot dependency, ~2s for all 7 types. Seeded from
body_id for reproducibility. Resolves Q-064 (Godot 3D planet plugin
evaluation — superseded by headless Python approach).

Assets at client/assets/planets/, 512×512 RGBA, displayed at 240×240 in
the body-info-panel navigator and GTTR arrival window.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 08:19:06 +02:00
co-authored by Claude Sonnet 4.6
parent b5cb93203b
commit 1cffc83dd7
10 changed files with 670 additions and 1 deletions
+157
View File
@@ -0,0 +1,157 @@
---
title: "Planetary Screenshot Spec — v0.1"
description: "Procedural planet sphere renders for the GTTR body-info-panel and wiki pages. One image per biome_summary type."
type: design
status: active
ticket: "#779"
decision_refs: []
author: "Araminta"
created: 2026-04-05
updated: 2026-04-05
---
# Planetary Screenshot Spec — v0.1
**Ticket:** #779
**Author:** Araminta
**Date:** 2026-04-05
**Status:** Active — assets delivered, awaiting client integration
---
## Display Context
Planet screenshots appear in the **body-info-panel** navigator (wireframe:
`docs/design/wireframes/navigator/body-info-panel.json`):
| Property | Value |
|----------|-------|
| Container | `planet-screenshot` — 360×360px, `#111820` background |
| Sphere display | 240×240px ellipse within the container |
| Z-context | Implant fullscreen (z=20), not gameplay layer |
| Background | `#0d1117` (navigator panel) |
In the **GTTR arrival window** (diegetic implant display during transit), the same
asset appears with the same proportions — one image per destination planet.
---
## Asset Inventory
**Location:** `client/assets/planets/`
**Format:** PNG, 512×512px, RGBA
**Display:** Scaled to 240×240 within a 360×360 container
| File | `biome_summary` value | Character |
|------|-----------------------|-----------|
| `planet_temperate.png` | `temperate` | Blue ocean, amber-green continents, cloud cover, polar caps |
| `planet_temperate_terminator.png` | `temperate_terminator` | Half gold-scorched day face, half frozen dark face, sharp terminator |
| `planet_oceanic.png` | `oceanic` | Deep blue water world, heavy cloud, scattered archipelago |
| `planet_arid.png` | `arid` | Warm reddish-brown, dusty, sparse thin polar caps |
| `planet_frozen.png` | `frozen` | White-blue ice, exposed grey rock at mid-latitudes |
| `planet_volcanic.png` | `volcanic` | Dark basalt, orange lava cloud patterns |
| `planet_barren.png` | `barren` | Cratered grey-brown, no atmosphere glow |
---
## Generation Pipeline
**Script:** `spikes/planet-renders/generate_planets.py`
```bash
# Regenerate all types
python3 spikes/planet-renders/generate_planets.py
# Single type
python3 spikes/planet-renders/generate_planets.py --type temperate
# Custom output location
python3 spikes/planet-renders/generate_planets.py --output-dir path/to/dir
```
**Dependencies:** `numpy`, `Pillow` (already in requirements)
**Technique:** Numpy ray-sphere intersection + Lambertian diffuse + specular +
procedural octave-sine texture. Runs without GPU. ~2s for all 7 types.
### Lighting rig
| Property | Value |
|----------|-------|
| Star direction (from surface) | (-0.55, 0.45, 0.70) normalized |
| Ambient | 0.22 (dark side is dim, not black) |
| Diffuse | 0.78 |
| Specular | 0.30 (modest glint) |
| Atmosphere rim glow | Blue-white, (1-rim)^5 × 0.7 |
### Texture approach
Procedural octave sine noise — no external noise library required. UV coordinates
from spherical mapping (lon, lat). Each planet type uses different:
- `seed` (shifts continent/feature pattern)
- `octaves` (detail level)
- `threshold` (land/ocean boundary)
- Color palette (per type)
---
## Binding to Atlas Data
Each planet in `systems.db` has a `biome_summary` field. The client selects the
matching planet image:
```gdscript
func planet_image_for_biome(biome: String) -> Texture2D:
var path = "res://assets/planets/planet_%s.png" % biome
if ResourceLoader.exists(path):
return load(path)
return load("res://assets/planets/planet_barren.png") # fallback
```
For `biome_summary = "temperate_terminator"`, the image maps directly to
`planet_temperate_terminator.png`.
---
## Coverage
| `biome_summary` value | Image | Inhabited planets using this type |
|-----------------------|-------|------------------------------------|
| `temperate` | ✓ | Majority of wave_1/wave_2 inhabited worlds |
| `temperate_terminator` | ✓ | Close-orbit M-dwarf worlds (Feldmark, Caparica) |
| `oceanic` | ✓ | Aquaculture worlds |
| `arid` | ✓ | Mars-analog, dry inner worlds |
| `frozen` | ✓ | Outer habitable zone, cold worlds |
| `volcanic` | ✓ | Young volcanic, active worlds |
| `barren` | ✓ | Airless rocky bodies, uninhabited |
| `gas_giant` | — | Not needed (gas giants not inhabited, no panel) |
---
## Visual Grammar Notes
All planet renders are consistent with the implant UI aesthetic:
- **Background:** `#04060a` space (near-black, matches `#0d1117` panel)
- **Star field:** Sparse white dots, random but seeded (reproducible)
- **Atmosphere rim:** Blue-white glow on all worlds with atmosphere — signals
habitability/breathability at a glance
- **Terminator worlds:** Gold/dark split communicates the concept without labels
- **Barren worlds:** No rim glow — instantly reads as airless
The renders are deliberately non-photorealistic. They're what the player's implant
processes during transit — a data-layer visualization, not a photograph.
---
## Future Additions
When new `biome_summary` types are added to the atlas schema, add a new renderer
function to `generate_planets.py` following the existing pattern. The functions
are self-contained — no cross-dependencies.
Potential additions as the Reach fills out:
- `jungle` — dense green, high cloud, equatorial band
- `desert` (distinct from `arid` — hotter, brighter orange)
- `swamp` — dark green-brown
- `gas_giant_banded` — for the implant wiki page of orbital gas giants