feat(cosmobiologia): esfera celeste 3D — la carta como objeto rotable

GPUI no es 3D y empotrar wgpu sería frágil; la esfera celeste es de
alambre —círculos máximos y puntos— y eso se proyecta a software con
trigonometría pura. Cada superficie ya sabe dibujar DrawCommand, así
que el módulo nuevo solo decide dónde cae cada trazo: una esfera real,
rotable, sin una línea de GPU.

- cosmobiologia-render/sphere3d.rs: marco eclíptico (z=0), proyección
  ortográfica con yaw/pitch, eclíptica + ecuador celeste inclinado por
  la oblicuidad (se cruzan en los equinoccios, como en el cielo),
  rejilla de meridianos/paralelos, signos, ángulos y cuerpos natales.
  Algoritmo del pintor + atenuación del hemisferio lejano. 5 tests.
- compose_sphere emite Vec<DrawCommand> — lo consumen igual el canvas
  gpui y el SVG del cliente web.
- cosmobiologia-canvas: modo esfera 3D en el lienzo (tecla V o el botón
  flotante «Esfera 3D»), drag para orbitar, traductor DrawCommand→GPUI.

Falta (2da capa): el horizonte local + día/noche — necesita la latitud
geográfica, que aún no viaja en el RenderModel.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-22 18:38:21 +00:00
parent 7695dbf3ce
commit 6a0781c0a8
4 changed files with 809 additions and 2 deletions
@@ -582,7 +582,7 @@ fn svg_escape(s: &str) -> String {
.replace('"', "&quot;")
}
fn sign_unicode(name: &str) -> &'static str {
pub(crate) fn sign_unicode(name: &str) -> &'static str {
match name {
"aries" => "",
"taurus" => "",
@@ -622,7 +622,7 @@ fn planet_unicode(name: &str) -> &'static str {
/// Glyph del cuerpo con sufijo "℞" si está retrógrado — concatenación
/// directa en el text para no agregar más comandos por planeta.
fn planet_unicode_with_retro(name: &str, retrograde: bool) -> String {
pub(crate) fn planet_unicode_with_retro(name: &str, retrograde: bool) -> String {
if retrograde {
format!("{}", planet_unicode(name))
} else {