feat(tahuantinsuyu): fase 15 — badges de overlays activos en el footer

Cuando hay overlays activos, debajo del info_row aparecen pills con
los nombres de cada uno (Natal, Tránsito ahora, Progresión 38.2a,
Sinastría · Ana, Saturn return 29a) — el usuario ve de un vistazo qué
está mirando sin tener que mapear los anillos manualmente.

El border de cada pill toma color según a qué slot del wheel
pertenece: outer ring (transit/synastry/planetary_return) →
palette.angle_highlight (dorado), inner overlays (progression/
solar_arc) → palette.house_cusp (tono apagado), natal → neutro.
Permite leer la pila de izquierda a derecha y ubicar visualmente cada
glyph del wheel.

- engine: nuevo OverlayMeta { module_id, label } + campo overlays:
  Vec<OverlayMeta> en RenderModel. build_render_model lo inicializa
  vacío; bridge::compose pushea un OverlayMeta por cada
  PipelineRequest después de su build_*_overlay correspondiente. Helper
  push_overlay_meta(render, id, label). Labels: "Tránsito ahora",
  "Progresión {age:.1}a", "Solar Arc {age:.1}a", "Sinastría · {name}"
  (lee partner_chart.label antes de mover el Box al builder),
  "{Body} return {age:.0}a" (usa eternal_sky body.name()).
- canvas: render_wheel separa el viejo footer en info_row (Asc/MC/ms +
  offset + hotkeys) y un badges_row opcional. badges_row aparece solo
  cuando render.overlays != empty. Pill helper centralizado: bg
  panel_alt, border 1px, text size 10, rounded 10. Border color
  decidido por module_id para correlacionar con el ring visual.

Compatible con compute_mock (que setea overlays = vec![] — ningún
mock badge). Persiste sin cambios — los configs siguen guardando su
estado, los OverlayMeta se reconstruyen en cada compose desde los
requests activos.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-17 11:34:54 +00:00
parent 6d572c81ca
commit 1232e39397
3 changed files with 96 additions and 2 deletions
@@ -17,7 +17,7 @@ use eternal_sky::{Ayanamsha, Body, EphemerisSession, Instant as ESInstant, Obser
use tahuantinsuyu_model::{Chart, HouseSystem, StoredChartConfig, Zodiac};
use crate::{EngineError, Geometry, Glyph, Layer, LayerKind, LineSeg, RenderModel};
use crate::{EngineError, Geometry, Glyph, Layer, LayerKind, LineSeg, OverlayMeta, RenderModel};
// =====================================================================
// Sesión global cacheada
@@ -254,15 +254,32 @@ pub fn compose(
match req {
crate::PipelineRequest::Transit => {
build_transit_overlay(&natal, &config_e, observer, ESInstant::now(), &mut render)?;
push_overlay_meta(&mut render, "transit", "Tránsito ahora".into());
}
crate::PipelineRequest::SecondaryProgression { target_age_years } => {
build_progression_overlay(&natal, *target_age_years, &mut render)?;
push_overlay_meta(
&mut render,
"progression",
format!("Progresión {:.1}a", target_age_years),
);
}
crate::PipelineRequest::SolarArc { target_age_years } => {
build_solar_arc_overlay(&natal, *target_age_years, &mut render)?;
push_overlay_meta(
&mut render,
"solar_arc",
format!("Solar Arc {:.1}a", target_age_years),
);
}
crate::PipelineRequest::Synastry { partner_chart } => {
let partner_label = partner_chart.label.clone();
build_synastry_overlay(&natal, partner_chart, &mut render)?;
push_overlay_meta(
&mut render,
"synastry",
format!("Sinastría · {}", partner_label),
);
}
crate::PipelineRequest::PlanetaryReturn {
body,
@@ -282,6 +299,11 @@ pub fn compose(
*target_age_years,
&mut render,
)?;
push_overlay_meta(
&mut render,
"planetary_return",
format!("{} return {:.0}a", body_e.name(), target_age_years),
);
}
}
}
@@ -808,9 +830,17 @@ fn build_render_model(
descendant_deg,
imum_coeli_deg,
layers: vec![sign_dial, houses, bodies, aspects_layer],
overlays: Vec::new(),
}
}
fn push_overlay_meta(render: &mut RenderModel, module_id: &str, label: String) {
render.overlays.push(OverlayMeta {
module_id: module_id.to_string(),
label,
});
}
/// Mapea el orb absoluto a una opacidad — los aspectos más exactos se
/// pintan más fuerte, los flojos casi se desvanecen.
fn orb_to_opacity(orb_deg: f64, kind: EAspectKind) -> f32 {