La «piel» de una esfera celeste no son continentes —esos van en la
Tierra— sino las estrellas y la Vía Láctea. Y a diferencia del brillo
especular (fijo a la pantalla), esta piel gira CON la esfera, así que
delata la rotación de un vistazo.
- Campo de estrellas isótropo, decorativo (no un catálogo real),
generado con un hash determinista — no titila entre frames.
- Vía Láctea: una sobredensidad de estrellas tenues a lo largo del
plano galáctico, ubicado con el polo galáctico real (J2000, AR
192.859° / Dec +27.128°).
- Estrellas con brillo y tinte variables (azuladas / cálidas),
atenuadas por profundidad. Van detrás de la rejilla, delante del
sombreado — un fondo de planetario. Solo en tema oscuro.
36 tests verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sobre el batch 1 (eclíptica + ecuador + cuerpos):
- Horizonte local: círculo máximo perpendicular al cénit, derivado de
la latitud geográfica y el RAMC. El cénit (declinación φ, AR RAMC,
llevado al marco eclíptico) es el «punto del observador» — marcado
como tal, con su nadir y el meridiano local.
- Día/noche: los cuerpos bajo el horizonte se atenúan — de un vistazo
se ve qué planetas estaban sobre la tierra en el momento de la carta.
- Marcadores de polos: eclípticos (punto dorado) y celestes (anillo +
cruz, etiquetados PN/PS) — el ángulo entre ambos ejes ES la
oblicuidad, ahora visible.
- Relieve de la esfera: disco base + degradado radial + brillo
especular desplazado a la luz — volumen sin gradientes nativos.
- RenderModel gana `geo_latitude_deg` (#[serde(default)]); el bridge
lo puebla desde birth_data.
Verificación: 2 tests nuevos fijan la construcción del cénit — está a
la colatitud del polo celeste, y cénit/polo/MC son coplanares (el
plano del meridiano), lo que ancla el RAMC. 35 tests verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
El corpus ya rebana la carta en tajadas vivenciales: una sola
configuración mirada plano a plano, sin promediar la contradicción.
- Colocacion / AspectoEnCarta: la posición real de un planeta en una
carta — el puente entre el motor astronómico y las claves del JOIN.
- combinaciones_de_carta: deriva todas las CombinacionId de una carta.
- rebanar_por_dominio: la tomografía — cada planeta@cN cae en el
dominio de su casa, cada planeta·signo hereda el de su casa, y un
aspecto puentea apareciendo en las dos tajadas que conecta.
- Corpus::interpretar_por_dominio: el JOIN agrupado por dominio,
entrada directa del gráfico «por tajadas».
- CombinacionId acepta el alias ASCII '/' del punto medio '·'.
- ejemplo.ron: plantilla cargable y comentada del corpus.
- GUIA.md: los pasos exactos para generar el corpus a mano.
12 tests verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El corpus es la biblioteca de interpretación indexada: fragmentos de
texto de los libros (y del astrólogo) etiquetados por la combinación
astrológica que describen. NO calcula nada — las reglas las computa el
motor; el corpus sólo guarda evidencia citable y la sirve por JOIN.
Esquema TIPADO (la astrología tiene gramática — planeta=función,
signo=estilo, casa=dominio, aspecto=relación; no son vectores
intercambiables de un espacio plano):
- CombinacionId — la «etiqueta de código de barras», con variantes por
tipo de combinación; el aspecto normaliza el orden de sus extremos.
- Arquetipo / TipoArquetipo — los bloques con su PerfilSemantico
(dimensiones con nombre que define el astrólogo, no el código).
- Pasaje — texto citado + fuente + combinación.
- Dominio — el plano vivencial (Vital/Social/Psíquico) por casa.
- Corpus::interpretar — el JOIN: combinaciones de la carta → pasajes.
Cobertura total; la SÍNTESIS es de una capa superior.
6 tests verdes. La capa de composición (deducir combinaciones no
leídas) queda explícitamente sin construir — es un problema de diseño
abierto, no un producto Hadamard ingenuo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El rectificador deja la aproximación y pasa a la trigonometría exacta,
con precisión de segundo — el "microajuste argentino".
LA MATEMÁTICA. El rectificador ya NO usa el modelo simplificado
(directed_longitude, rotación uniforme de RA + convergencia GR). Ahora
usa `eternal_astrology::primary_direction::all_directions` — el método
Placidus-mundano: semi-arcos diurnos/nocturnos bajo el polo de cada
cuerpo, la trigonometría esférica de la escuela ascensional. No se
reimplementó nada: la matemática, ya probada, vive en eternal; el
engine sólo aporta la capa de optimización.
- error_de_carta: por cada evento, la distancia en años a la dirección
primaria que perfecciona más cerca; el error total es la suma. Es la
función de coste del microajuste — el valle es la hora real.
PRECISIÓN DE SEGUNDO. compute_natal_chart / build_eternal_inputs /
natal_cache pasan a trabajar en SEGUNDOS (compose convierte ×60). El
rectificador barre en dos pasadas: gruesa minuto a minuto sobre la
ventana (el perfil que dibuja la curva), fina segundo a segundo en
±60 s alrededor del mejor minuto.
- Rectificacion: mejor_offset_segundos; el perfil va en segundos.
- UI: panel y curva muestran «±Xm Ys · error N.NNa». Las barras siguen
siendo clicables (scrub a esa hora candidata).
Tests verdes (engine 12, render 28). Limitación conocida: all_directions
es sólo directo — converso necesita crecer en eternal (upstream).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cada barra de la curva del barrido se vuelve clicable: un clic lleva
la carta a esa hora candidata, reusando el scrub de tiempo del
jog-dial (CanvasEvent::TimeOffsetChanged, ya cableado en el shell).
Cierra el lazo del rectificador: ahora se puede inspeccionar sobre el
wheel cualquier hora del barrido, no sólo leer la ganadora.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tercer y último incremento: la visualización. El rectificador ya
muestra POR QUÉ una hora gana, no sólo cuál.
- cosmobiologia-canvas: CanvasState gana `rectificacion` +
`set_rectificacion`. render_rectify_profile dibuja el barrido como
un histograma en el footer — cada barra es una hora candidata, su
altura crece cuanto menor el puntaje; la barra más alta (el valle
del puntaje) es la hora rectificada, resaltada. Etiqueta los hitos
(mejor, 0, extremos).
- shell: run_rectificacion publica el Rectificacion al canvas además
del resumen textual al panel.
Con esto el rectificador automático (#67) queda completo: motor de
escaneo GR + UI de entrada + visualización del perfil.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Segundo incremento: el rectificador ya es usable de punta a punta
desde el panel, sin infraestructura de UI nueva.
- cosmobiologia-panel: Control::TextInput pasa a renderizarse desde
string_state — deja de ser un display estático y se vuelve un campo
de sólo-lectura que el shell escribe vía set_string (resultados,
etiquetas).
- cosmobiologia-modules: el módulo primary_directions gana 3 sliders
«Evento N · edad» (0 = ranura sin usar), un Action «Rectificar
hora» y un TextInput «Resultado».
- shell: run_rectificacion lee las edades de los sliders, llama a
engine::rectificar (ventana ±15 min, paso 1) y escribe la hora
rectificada + el puntaje en el campo Resultado del panel.
El rectificador queda funcional: activar GR → fijar edades de eventos
→ «Rectificar hora» → leer el resultado. Falta sólo la curva del
perfil del barrido como visualización (incremento opcional).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Primer incremento del rectificador automático (#67): dado un conjunto
de eventos conocidos de la vida del sujeto, barre las horas de
nacimiento candidatas y devuelve la que mejor los explica vía el
Sistema GR. La killer feature pro — desbloqueada al completar el GR.
- cosmobiologia-render: `convergencia_minima` — medida CONTINUA de qué
tan bien una carta explica un evento (suma de orbes del directo +
converso más cerrados sobre un punto natal). 3 tests.
- cosmobiologia-engine: módulo `rectify` — `rectificar` barre la
ventana de horas candidatas; por candidata computa la carta (una
vez, cacheada) y mide la convergencia GR a la edad de cada evento;
elige el puntaje mínimo. Devuelve el perfil completo del barrido
para que la UI lo dibuje como curva. Test end-to-end con eternal.
- bridge: `compute_natal_chart`/`body_symbol`/consts GR → pub(crate).
Falta: la UI (capturar eventos conocidos, lanzar el barrido, mostrar
la curva y la hora rectificada).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El módulo Uranian sólo listaba las fórmulas como texto; ahora también
las muestra geométricamente.
- cosmobiologia-canvas: render_uranian_dial pinta un eje horizontal
0-90° con cada cuerpo natal proyectado en su longitud mod 90. Ticks
en las divisiones duras (0/22½/45/67½/90°); los cuerpos que forman
una fórmula uraniana van resaltados, y los clusters densos se
escalonan en filas para legibilidad. La sección del footer combina
el dial geométrico con la lista de pills de fórmulas.
- El dial aparece siempre que el módulo Uranian está activo (antes la
sección sólo salía si había grupos detectados).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Completa la feature de armónicos: además de la carta armónica, ahora
hay un espectro que guía qué armónico mirar.
- cosmobiologia-render: harmonic_spectrum computa la fuerza de cada
armónica 1-32 (suma de cercanía a conjunción exacta de los pares de
cuerpos en esa armónica). apply_harmonic lo puebla + expone el
armónico activo. Campos RenderModel.harmonic / .harmonic_spectrum.
2 tests nuevos (el pico cae en la armónica resonante).
- cosmobiologia-canvas: render_harmonic_spectrum pinta el histograma
en el footer; cada barra es clicable y emite HarmonicSelected — un
clic salta a esa armónica. La barra activa va resaltada.
- shell: select_harmonic fija el slider del módulo natal y recompone.
- modules: el slider de armónico pasa de 1-20 a 1-32 (rango del
espectro).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El slider "Armónico" del NatalModule existía pero no hacía nada.
Ahora re-renderiza la carta en el armónico de orden N.
- cosmobiologia-render: módulo `harmonic` agnóstico — apply_harmonic
transforma los cuerpos natales a (longitud·N) mod 360 y recomputa
los aspectos sobre las posiciones armónicas (conjunción, oposición,
trígono, cuadratura, sextil). Las casas se conservan como marco.
6 tests (incluye: quintil natal → conjunción en H5).
- cosmobiologia-engine: NatalOptions.harmonic; compose lo aplica tras
la pasada natal, antes de los overlays. Test end-to-end.
- shell: build_natal_options lee el slider del módulo natal.
El título anota "· HN". Falta: histograma de fuerza por armónico.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tercer y último incremento del Sistema GR: en modo GR (direcciones
primarias activas) el jog-dial deja de rotar el wheel y pasa a
scrubear la edad en vivo.
- canvas: CanvasState::gr_active() detecta el modo; on_jog_move emite
CanvasEvent::GrAgeDelta (años por grado de jog, sensibilidad 0.1)
en vez de rotar; on_jog_up no aplica snap de tiempo.
- shell: scrub_gr_age acumula el delta sobre target_age_years del
módulo primary_directions, clampa a [0,120], sincroniza el slider
del panel y recompone — los glifos dirigidos y el HUD se mueven en
vivo bajo el cursor.
Con esto el Sistema GR queda completo: cómputo de triggers, resaltado
de convergencias, HUD de rectificación y scrubbing live.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Segundo incremento del Sistema GR: el canvas ahora hace visible la
rectificación.
- Resaltado de convergencias: por cada punto natal donde un directo y
un converso coinciden dentro del micro-orbe, un eje brillante cruza
la zona del dual-ring hasta el cinturón natal, con marcador glow.
- HUD lateral: columna a la derecha del wheel cuando GR está activo,
con los triggers ordenados por orbe. Color rojo→gris según orbe; las
convergencias llevan ✦ y fondo resaltado.
paint_wheel recibe los gr_triggers; render_wheel monta el body como
fila wheel+HUD sólo en modo GR.
Falta: scrubbing live del jog-dial mapeado a la edad.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Primer incremento del Sistema GR (García Rosas): la engine, además del
dual-ring directo/converso, ahora computa los triggers de rectificación
y detecta las convergencias directo+converso sobre un mismo punto natal.
- cosmobiologia-render: módulo `gr` agnóstico — tipos GrTrigger/GrDirection
+ compute_gr_triggers (emparejamiento puro, 7 tests). Campo gr_triggers
en RenderModel (serde-default, back-compat).
- cosmobiologia-engine: build_primary_directions_overlay computa los
triggers contra cuerpos natales + 4 ángulos; orbe HUD 2°, micro-orbe
de evento 5'. Test end-to-end con eternal.
Falta: resaltado del evento en el canvas, HUD lateral, scrubbing live.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El render agnóstico ya no es un esqueleto — porta al WASM la mayoría
de los detalles visuales que tenía solo el canvas gpui nativo:
- palette.rs: Palette dark/light replicando AstroPalette del theme
nativo, pero en Rgba (no Hsla de gpui). Métodos planet/aspect/sign
para resolver color por id simbólico, + house_ring con hue-shift.
- CompositionOpts extendido: palette, dial_3d, draw_ascensional_cross,
show_coord_labels, show_minor_aspects. Defaults razonables.
- compose_wheel ahora dibuja: background panel, dial 3D bevel (4
strokes concéntricos con alpha decreciente), subdivisiones cada 10°
con sign boundaries reforzados, signos con color elemental, casas
topocéntricas + geocéntricas en sus rings canónicos, cuerpos con
spread anti-solapamiento + clusters + disco coloreado por planeta,
coord labels "DD°MM'♈" en natal, aspectos con width inversa al
orbe + filtrado opcional de minors, cruz ascensional dashed +
pills ASC/MC/DESC/IC.
- cosmobiologia-web: nuevo render_model_to_svg_themed(dark: bool)
para que el cliente JS elija palette según preferencia del UA.
Tests del módulo math siguen verdes (10/10). Smoke test del server:
/api/sky.svg ahora emite 22 circles, 77 lines, 52 texts con paleta
real (vs ~6 circles, 24 lines, 36 texts del esqueleto previo).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cierra el requerimiento del módulo web. El cliente puede correr en
modo WASM (render local, scrubbing instantáneo, sin round-trip) o
caer al SSR (server compone el SVG) si el bundle WASM no está
desplegado. Switch automático sin configuración.
cosmobiologia-web (crate nuevo, cdylib + rlib):
- `lib.rs` con un único export wasm-bindgen
`render_model_to_svg(json, size, rot_offset_deg) -> String` que
deserializa un `RenderModel`, llama `compose_wheel` +
`draw_commands_to_svg` de cosmobiologia-render, y devuelve el
SVG inline listo para `wheel.innerHTML = svg`.
- Cargo.toml con `wasm-bindgen` + `getrandom` con feature
`wasm_js` solo bajo `target_arch = "wasm32"` (en nativo no se
arrastran).
- `.cargo/config.toml` con `--cfg getrandom_backend="wasm_js"`
para que la transitividad
`uuid → cosmobiologia-model → cosmobiologia-render` compile a
wasm32-unknown-unknown.
- `cargo check -p cosmobiologia-web` pasa en nativo (valida la
signature). Build WASM real lo dispara el usuario con
`wasm-pack build --target web --out-dir ../../../apps/
cosmobiologia-server/static/wasm` — comando documentado en
DEPLOY.md y en doc del crate.
cosmobiologia-server — soporte cliente WASM:
- Nuevo flag `--static-wasm <dir>` (default = static/wasm relativo
al cwd). Si el directorio existe, los archivos WASM se sirven
en `/static/wasm/*`. Si no existe, devuelve 404 y el cliente
cae al SSR.
- ServeDir de `tower-http` para fileserver simple.
index.html:
- Nueva función `tryLoadWasm()` que hace `import dinámico` del
módulo WASM al boot. Si carga OK, `wasm` global queda set; si
falla (archivo no existe o error de WASM), se loguea info y
sigue.
- `refreshSelected()` ahora hace fetch del RenderModel JSON
(`/api/sky` o `/api/charts/:id/render`); si hay WASM, llama
`wasm.render_model_to_svg(json)` localmente; si no hay WASM o
el render WASM falla, hace fetch del SVG SSR como fallback.
- Info row muestra "WASM" o "SSR" según el modo activo —
visualmente claro qué pipeline está corriendo.
cosmobiologia-server/DEPLOY.md (nuevo):
- Build del binario + build del WASM (con wasm-pack).
- systemd service template (sandboxing básico: ProtectSystem
strict, ProtectHome, PrivateTmp, NoNewPrivileges).
- Caddyfile y nginx para reverse proxy con TLS.
- DNS: A records para cosmobiologia.gioser.net + api.*.
- CORS: warnings sobre permissive vs producción multi-usuario.
- Separación demo público (DB vacía en VPS) vs desktop personal
(DB compartida en `~/.local/share/cosmobiologia/`).
- Backup con SQLite `.backup`.
- Smoke test post-deploy con curl.
- Tabla de referencia de TODOS los endpoints.
Tests: 10 verdes (cosmobiologia-render::math). El cliente WASM
no agrega tests propios — la lógica testeable vive en render.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fase 3a — render web operativo sin WASM. Demo funcional inmediata
con server-side rendering del SVG; el cliente WASM puro se hace en
fase 3b cuando wasm-pack / wasm-bindgen-cli esté instalado.
cosmobiologia-render — nuevo módulo `draw`:
- `Rgba { r, g, b, a }` color agnóstico (no Hsla, no hex CSS).
- `DrawCommand` enum tagged-serde: `Circle`, `Line`, `Text`. Listo
para WASM o nativo — solo primitivas.
- `CompositionOpts { size, rot_offset_deg, include_bodies }`.
- `compose_wheel(model, opts) -> Vec<DrawCommand>` primera versión:
anillo zodiacal (A+B), 12 cusps cada 30°, glyphs de signos,
corona de casas (C+D), cusps de casas (Asc/IC/Desc/MC con peso
doble), house numbers, anillo de aspectos (E), líneas de
aspectos coloreadas por kind, glyphs de cuerpos natales con
disco halo.
- `draw_commands_to_svg(cmds, size) -> String` serializa la lista
a SVG inline. SVG-escape, `text-anchor` configurable, `dominant
-baseline=central` para centrar verticalmente.
Pendiente en `compose_wheel` (extender en commits siguientes,
copiando lo del canvas gpui): spread anti-solapamiento, clusters
compartidos, coord labels, dial 3D bevel, vignette, themes
PrintColor/PrintBW. Por ahora es un MVP suficiente para verificar
end-to-end y para que el usuario tenga algo visible YA.
cosmobiologia-server:
- Nuevos endpoints:
* `GET /` → HTML del cliente (single-page)
* `GET /api/sky.svg` → SVG agnóstico del "cielo ahora"
* `GET /api/charts/:id/wheel.svg` → SVG agnóstico de carta con
overlays via query (offset,
transit, prog, sa, pd)
- Página HTML embebida (`include_str!` de `static/index.html`):
* Sidebar con tree (groups → contacts → charts), click selecciona
* "⏱ Cielo ahora" siempre disponible como botón rápido
* Toolbar con input offset minutos + checkbox tránsito + botón
refresh + botón download SVG
* Botones "Nuevo grupo / Nuevo contacto" con prompt + POST
* Wheel renderizado en SVG inline, info row con título/asc/mc/ms
Smoke test:
cargo run -p cosmobiologia-server -- --port 18787
curl / → HTML (página completa)
curl /api/sky.svg → 12 KB SVG con 17 circles +
51 lines + 36 texts
curl /api/tree → árbol JSON
curl POST /api/groups → crea grupo
Browser http://127.0.0.1:8787 → wheel visible
Próximo (fase 3b): cliente cdylib WASM `cosmobiologia-web` que
reemplace el SSR — recibe RenderModel JSON, llama compose_wheel +
draw_commands_to_svg en WASM, monta SVG via DOM. Trade-off: el
SSR de hoy es 12 KB transferidos por click (sólido); WASM
descarga ~150 KB una sola vez y luego compone localmente
(scrubbing instantáneo, sin round-trip al server).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rename clean del proyecto astrológico antes de empezar el módulo
web (fase 2 = server axum, fase 3 = cliente WASM). Hacerlo ahora
ahorra refactor de URLs, package.json, paths de assets HTML y
deploy configs que aparecerían con el nombre en cuanto exista el
server.
Mecánica:
- `git mv` de los 10 crates de módulo + 2 apps:
* `crates/modules/tahuantinsuyu/` → `cosmobiologia/`
* `crates/modules/tahuantinsuyu/tahuantinsuyu-*` →
`cosmobiologia/cosmobiologia-*`
* `crates/apps/tahuantinsuyu` y `tahuantinsuyu-cli` análogos.
- Sed sobre todos los `.rs` y `.toml`: `tahuantinsuyu` →
`cosmobiologia` (cubre crate names, deps paths, use
statements, ProjectDirs literals, binary names).
- Workspace `Cargo.toml`: members con paths nuevos.
- Memoria del proyecto (`~/.claude/.../memory/project_*.md`)
actualizada.
Cero leftovers: `grep -rn tahuantinsuyu --include="*.rs"
--include="*.toml" crates/` devuelve vacío.
DB & XDG: clean slate. La nueva app arranca con DB vacía en
`$XDG_DATA_HOME/cosmobiologia/charts.db`. Si tenías cartas
guardadas, viven todavía en `~/.local/share/tahuantinsuyu/` —
las podés migrar manualmente con un `cp`.
IDs UI inalterados: el prefijo `tts-` de gpui ElementIds queda
igual (cosmético, no afecta funcionalidad). Cambiarlo a `cb-`
ahora sería 3-4 líneas más de sed pero ningún beneficio
operativo.
Tests: 20 verdes (10 shell + 10 render math). Compila full:
`cargo check -p cosmobiologia` OK.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>