gioser

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Sutichaykuna

feat(cosmobiologia): esfera 3D — switch de constelaciones + luz de la Vía Láctea

- Switch de constelaciones: botón flotante «● Constelaciones» (o tecla
  B) que las enciende y apaga en la esfera 3D.
- La luminosidad se reparte: el brillo especular fijo a la pantalla se
  bajó mucho (no giraba, se sentía despegado), y en su lugar la Vía
  Láctea aporta un resplandor difuso a lo largo del plano galáctico —
  que SÍ gira con la esfera. Más intenso hacia el centro galáctico
  (Sagitario, como en el cielo real) y atenuado bajo el horizonte
  local: la franja como se ve desde la Tierra esa noche.

42 tests verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

6e30dc2d7288b691aec553b8261f818c6f9dbba9 · ruwaq sergio · (5 killa ñawpaq) · tayta cfb37af0c · kay commitpi sach'ata qhaway

Semántico sayk'uy · 12

crates/modules/cosmobiologia/cosmobiologia-canvas/src/lib.rs

crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs

2 qillqakuna · +98 −5

diff --git a/crates/modules/cosmobiologia/cosmobiologia-canvas/src/lib.rs b/crates/modules/cosmobiologia/cosmobiologia-canvas/src/lib.rs
index 3855b35..43952af 100644
--- a/crates/modules/cosmobiologia/cosmobiologia-canvas/src/lib.rs
+++ b/crates/modules/cosmobiologia/cosmobiologia-canvas/src/lib.rs
@@ -171,6 +171,8 @@ pub struct CanvasState {
     pub sphere_3d: bool,
     /// Orientación de la esfera 3D — la muta el drag.
     pub sphere_view: SphereView,
+    /// Si se dibujan las figuras de constelaciones en la esfera 3D.
+    pub show_constellations: bool,
     drag_jog: Option<JogDragState>,
     drag_pan: Option<PanDragState>,
     drag_sphere: Option<SphereDragState>,
@@ -258,6 +260,7 @@ impl Default for CanvasState {
             rectificacion: None,
             sphere_3d: false,
             sphere_view: SphereView::default(),
+            show_constellations: true,
             drag_jog: None,
             drag_pan: None,
             drag_sphere: None,
@@ -383,6 +386,12 @@ impl AstrologyCanvas {
         cx.notify();
     }
 
+    /// Enciende o apaga las figuras de constelaciones en la esfera 3D.
+    pub fn toggle_constellations(&mut self, cx: &mut Context<'_, Self>) {
+        self.state.show_constellations = !self.state.show_constellations;
+        cx.notify();
+    }
+
     /// Resetea zoom y pan a sus defaults (1.0 y 0,0). No toca rotation
     /// ni time offset — esos son ortogonales y tienen su propio reset.
     pub fn reset_view(&mut self, cx: &mut Context<'_, Self>) {
@@ -821,6 +830,10 @@ impl AstrologyCanvas {
                 self.toggle_sphere(cx);
                 return;
             }
+            "b" | "B" => {
+                self.toggle_constellations(cx);
+                return;
+            }
             _ => return,
         };
         self.toggle_layer(kind, cx);
@@ -914,6 +927,7 @@ impl Render for AstrologyCanvas {
                 &theme,
                 render,
                 self.state.sphere_view,
+                self.state.show_constellations,
                 self.state.view_scale,
                 self.state.view_pan_x,
                 self.state.view_pan_y,
@@ -965,6 +979,36 @@ impl Render for AstrologyCanvas {
                 )
         });
 
+        // Switch de constelaciones — solo en modo esfera 3D.
+        let constellations_toggle = (matches!(self.state.mode, CanvasMode::Wheel { .. })
+            && self.state.sphere_3d)
+            .then(|| {
+                let on = self.state.show_constellations;
+                let label = if on {
+                    "● Constelaciones"
+                } else {
+                    "○ Constelaciones"
+                };
+                div()
+                    .absolute()
+                    .top(px(44.0))
+                    .right(px(12.0))
+                    .px(px(11.0))
+                    .py(px(5.0))
+                    .rounded(px(6.0))
+                    .bg(theme.bg_panel_alt.clone())
+                    .border_1()
+                    .border_color(theme.border)
+                    .text_size(px(11.0))
+                    .text_color(if on { theme.fg_text } else { theme.fg_muted })
+                    .cursor_pointer()
+                    .child(label)
+                    .on_mouse_down(
+                        MouseButton::Left,
+                        cx.listener(|this, _, _w, cx| this.toggle_constellations(cx)),
+                    )
+            });
+
         // Depth field: capa absoluta detrás del body, ocupa todo el
         // canvas. Vignette radial — el centro queda claro y los
         // bordes se oscurecen, dando profundidad sin "ruido" de
@@ -1005,6 +1049,7 @@ impl Render for AstrologyCanvas {
                     .child(body),
             )
             .children(sphere_toggle)
+            .children(constellations_toggle)
     }
 }
 
@@ -1080,6 +1125,7 @@ fn render_sphere(
     theme: &Theme,
     render: &RenderModel,
     view: SphereView,
+    show_constellations: bool,
     view_scale: f32,
     view_pan_x: f32,
     view_pan_y: f32,
@@ -1093,6 +1139,7 @@ fn render_sphere(
         } else {
             Palette::light()
         },
+        show_constellations,
         ..Default::default()
     };
     let commands = compose_sphere(render, &view, &opts);
diff --git a/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs b/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs
index 2508d98..a18f8a4 100644
--- a/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs
+++ b/crates/modules/cosmobiologia/cosmobiologia-render/src/sphere3d.rs
@@ -313,15 +313,16 @@ fn add_sphere_shading(
                 cy: center,
                 r: rad * (0.95 - 0.95 * t),
                 stroke: None,
-                fill: Some(glow.with_alpha(0.04)),
+                fill: Some(glow.with_alpha(0.028)),
                 stroke_w: 0.0,
             },
         ));
     }
-    // Brillo especular desplazado hacia la luz.
+    // Brillo especular desplazado hacia la luz — tenue: la luminosidad
+    // viva la reparte la Vía Láctea, que sí gira con la esfera.
     let hx = center - rad * 0.34;
     let hy = center - rad * 0.34;
-    const HALO: usize = 7;
+    const HALO: usize = 6;
     for i in 0..HALO {
         let t = i as f32 / (HALO - 1) as f32;
         items.push((
@@ -331,7 +332,7 @@ fn add_sphere_shading(
                 cy: hy,
                 r: rad * 0.5 * (1.0 - t),
                 stroke: None,
-                fill: Some(highlight.with_alpha(0.05)),
+                fill: Some(highlight.with_alpha(0.018)),
                 stroke_w: 0.0,
             },
         ));
@@ -562,6 +563,10 @@ fn add_point_marker(
 /// estándar IAU que fija el plano de la Vía Láctea.
 const GAL_POLE_RA: f32 = 192.859;
 const GAL_POLE_DEC: f32 = 27.128;
+/// Centro galáctico (Sgr A*, J2000): AR 266.405°, Dec −28.936°. Hacia
+/// ahí la Vía Láctea es más brillante.
+const GAL_CENTER_RA: f32 = 266.405;
+const GAL_CENTER_DEC: f32 = -28.936;
 
 /// Hash entero → f32 en [0,1). Determinista (variante de splitmix32):
 /// la misma entrada da siempre el mismo valor, así el campo de
@@ -659,6 +664,46 @@ fn add_starfield(items: &mut Vec<(f32, DrawCommand)>, proj: &Projector, size: f3
     }
 }
 
+/// El resplandor difuso de la Vía Láctea — una luminosidad repartida a
+/// lo largo del plano galáctico, no un brillo fijo a la pantalla. Gira
+/// con la esfera. Es más intensa hacia el centro galáctico (en
+/// Sagitario, como en el cielo real) y, si hay horizonte, se atenúa en
+/// la parte que queda bajo tierra esa noche — la franja como se ve
+/// desde la Tierra ese día.
+fn add_milky_way_glow(
+    items: &mut Vec<(f32, DrawCommand)>,
+    proj: &Projector,
+    eps: f32,
+    size: f32,
+    zenith: Option<Vec3>,
+) {
+    let gpole = rot_x(equatorial_dir(GAL_POLE_RA, GAL_POLE_DEC), eps);
+    let gcenter = rot_x(equatorial_dir(GAL_CENTER_RA, GAL_CENTER_DEC), eps);
+    let band = Rgba::opaque(0.78, 0.82, 0.96);
+    for p3 in great_circle_perp(gpole, 54) {
+        // Más brillo hacia el centro galáctico.
+        let toward = (p3.dot(gcenter) * 0.5 + 0.5).clamp(0.0, 1.0);
+        let bright = 0.28 + 0.72 * toward * toward;
+        // Atenuada bajo el horizonte local (no se ve esa noche).
+        let vis = match zenith {
+            Some(z) if p3.dot(z) < 0.0 => 0.40,
+            _ => 1.0,
+        };
+        let p = proj.project(p3);
+        items.push((
+            p.depth - 4.0,
+            DrawCommand::Circle {
+                cx: p.x,
+                cy: p.y,
+                r: size * 0.045,
+                stroke: None,
+                fill: Some(band.with_alpha(0.030 * bright * vis * depth_alpha(p.depth))),
+                stroke_w: 0.0,
+            },
+        ));
+    }
+}
+
 // --- Estrellas fijas notables ----------------------------------------
 
 /// Latitud eclíptica (grados, J2000) de las estrellas fijas notables
@@ -982,8 +1027,9 @@ pub fn compose_sphere(
     // --- Cuerpo de la esfera: sombreado con volumen ---
     add_sphere_shading(&mut items, pal, center, rad);
 
-    // --- Cielo de fondo: estrellas + Vía Láctea (solo tema oscuro) ---
+    // --- Cielo de fondo: Vía Láctea + estrellas (solo tema oscuro) ---
     if opts.show_sky && pal.is_dark {
+        add_milky_way_glow(&mut items, &proj, eps, size, zenith);
         add_starfield(&mut items, &proj, size, eps);
     }