feat(cosmobiologia): Tierra interior — tinte mar/continente + día/noche

La Tierra interior ahora se lee como un planeta:

- Mar y continentes teñidos distinto: el mar es un disco azul, los
  continentes son polígonos rellenos de verde. Para eso se sumó la
  primitiva DrawCommand::Polygon (relleno + trazo) — agnóstica, con su
  traductor GPUI y su emisor SVG.
- Sombreado día/noche según el Sol de la carta: el hemisferio que mira
  al Sol se ilumina (resplandor concéntrico sobre el punto subsolar,
  que se apaga si el Sol queda detrás de la Tierra), el terminador
  marca la línea día/noche, y cada continente se tiñe verde claro u
  oscuro según esté de día o de noche. El observador se atenúa si
  naci­ó de noche.

42 tests verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-22 19:33:46 +00:00
parent 267e54f974
commit cfb37af0cf
3 changed files with 190 additions and 23 deletions
@@ -85,6 +85,16 @@ pub enum DrawCommand {
#[serde(default = "default_anchor")]
anchor: TextAnchor,
},
/// Polígono cerrado — lista de vértices, con relleno y/o trazo.
Polygon {
points: Vec<(f32, f32)>,
#[serde(default)]
fill: Option<Rgba>,
#[serde(default)]
stroke: Option<Rgba>,
#[serde(default = "default_stroke_width")]
stroke_w: f32,
},
}
fn default_stroke_width() -> f32 {
@@ -557,6 +567,25 @@ pub fn draw_commands_to_svg(commands: &[DrawCommand], size: f32) -> String {
x1, y1, x2, y2, color.to_css(), width, dash_attr
));
}
DrawCommand::Polygon { points, fill, stroke, stroke_w } => {
let pts: String = points
.iter()
.map(|(x, y)| format!("{:.2},{:.2} ", x, y))
.collect();
let fill_attr = match fill {
Some(c) => format!(" fill=\"{}\"", c.to_css()),
None => " fill=\"none\"".into(),
};
let stroke_attr = stroke
.map(|c| format!(" stroke=\"{}\" stroke-width=\"{}\"", c.to_css(), stroke_w))
.unwrap_or_default();
s.push_str(&format!(
"<polygon points=\"{}\"{}{}/>",
pts.trim_end(),
fill_attr,
stroke_attr
));
}
DrawCommand::Text { x, y, content, color, size: sz, anchor } => {
let anchor_attr = match anchor {
TextAnchor::Start => "start",