Activá el toggle "Tránsitos (ahora)" en el panel (o hotkey [T] sobre
el wheel): la engine computa una segunda NatalChart al instante
SystemTime::now() con el mismo observer y dibuja un anillo externo de
planet glyphs encima del natal, más las cross-aspects entre ambos
charts (sólo mayores). Las líneas cross van del ring de cuerpos
natales al ring externo de tránsitos, con stroke más fino y opacidad
más baja para no taparle el ojo a las aspectos natal-natal.
- engine/bridge.rs: extraídas build_eternal_inputs y
compute_natal_chart como helpers reutilizables. Nueva
compute_with_transits(chart, offset, transit_at) que llama
find_synastry_aspects entre natal y transit (AspectKind::MAJORS).
Atajo compute_with_transits_at_now usa ESInstant::now(). Las capas
extra van con module_id = "transit" y LayerKind::Outer /
LayerKind::Aspects para que el canvas las distinga.
- engine/lib.rs: re-export de compute_with_transits_at_now con el
mismo fallback al mock cuando feature `eternal-bridge` está off.
- canvas: nueva Radii::transits = 0.82, layout del wheel re-balanceado
(houses_outer 0.78, houses_inner 0.66, bodies 0.58, aspects 0.50)
para hacer lugar al anillo externo sin colisiones. paint_wheel:
detecta layers de transit por module_id, pinta dots + glifos en el
anillo nuevo + anillos guía sutiles. paint_cross_aspect_line con
stroke 0.7 entre los dos radios. Glyph overlay para Outer ring con
alpha 0.9 y font_size más chico que el natal. Hotkey [T] en
on_key_down toggle LayerKind::Outer.
- modules: NatalModule.controls() agrega toggle show_transits con
hotkey [T] (default false — no recomputar transits si nadie pidió).
- shell: nuevo show_transits flag. render_current despacha entre
compute_at_offset y compute_with_transits_at_now según el flag.
on_panel_event traduce ControlChanged show_transits a flip + redraw.
on_canvas_event: el toggle de LayerKind::Outer dispara show_transits
flip + render (no es un visibility toggle puro).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Time scrubbing por drag en el aro exterior del wheel: rota visualmente
mientras dura el drag, al soltar traduce el delta angular a minutos
(1° = 4 min sideral, CW = forward) y emite CanvasEvent::TimeOffsetChanged.
La Shell recomputa con engine::compute_at_offset y el ascendant rotado
queda en la nueva posición. Snap visual a 0° tras commit.
- engine: nueva variante compute_at_offset(chart, minutes) que suma
segundos al UTC base via add_seconds + Instant::from_utc y corre la
pipeline normal. compute() es ahora wrapper con offset=0.
- canvas: estado nuevo layer_visibility + drag_jog. Mouse handlers
registrados desde el paint callback (mismo patrón que splitter/tiled).
Hotkeys D/H/X/P toggle SignDial/Houses/Aspects/Bodies, R resetea
offset. FocusHandle + click-to-focus para recibir teclas. Indicador
⏱ ±Xd HH:MM en el footer con color highlight cuando el offset != 0.
paint_wheel + glyph overlays respetan layer_visibility (skip capas
ocultas).
- modules: NatalModule.controls() ahora expone show_sign_dial /
show_houses / show_aspects / show_bodies con hotkeys [D/H/X/P], más
el slider de armónico.
- panel: ControlPanel mantiene toggle_state cache (module_id, key) →
bool, inicializa desde defaults al cambiar de ChartKind. Click
invierte el toggle visualmente y emite ControlChanged. Nuevo
set_toggle(module, key, value) para que la Shell mantenga sync
cuando el canvas se autotogglea por hotkey.
- shell: nuevo current_chart + current_offset_minutes. render_current()
delega a compute_at_offset. Suscripción a CanvasEvent traduce
TimeOffsetChanged → re-render, LayerVisibilityChanged → panel sync.
Suscripción a PanelEvent::ControlChanged traduce show_* keys a
set_layer_visible sobre el canvas.
Todos los tests verdes. La fase 5 sumará módulos extra (transit,
progression, synastry, uranian) + extracción de eternal de lo que falte.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`BodyPlacement::is_retrograde` cambió entre versiones de eternal:
en commits viejos es `pub fn is_retrograde(&self) -> bool`, en más
nuevos es `pub is_retrograde: bool`. Cualquiera de las dos formas
rompe la otra al usar `p.is_retrograde()` o `p.is_retrograde`.
Leemos el campo crudo `pub longitude_rate_rad_per_day: f64` (estable
en ambas) y aplicamos `< 0.0` localmente — el bridge queda inmune a
ese refactor upstream.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bridge a eternal-astrology prendido por default. `engine::compute(chart)`
abre una EphemerisSession VSOP2013 (cacheada vía OnceLock global),
traduce los Stored* del modelo a BirthData/ChartConfig de eternal,
corre NatalChart::compute + find_aspects(modern_western) y devuelve un
RenderModel con cuatro capas: SignDial, Houses, Bodies, Aspects.
- tahuantinsuyu-engine: bridge.rs nuevo con map_house_system,
map_zodiac (incl. 8 ayanamshas), map_body_set, body_symbol,
aspect_kind_id. compute_mock se mantiene como fallback sin feature.
Errores tipados (EngineError::Eternal). Test real verde con datos
natales de demo.
- tahuantinsuyu-canvas: rewrite con gpui::canvas() + PathBuilder.
Pinta: sectores zodiacales coloreados por elemento (Fire/Earth/Air/
Water), anillos de sign-dial/houses/aspects, cusps zodiacales,
cusps de casas (con énfasis para Asc/MC/Desc/IC), líneas radiales
hasta el centro para los ejes, líneas de aspectos coloreadas por
kind con opacidad por orb, dots de cuerpos.
Glifos unicode (♈-♓ signos, ☉-♇ planetas, ☊☋⚷⚸ puntos) como divs
absolutos sobre el canvas. Marcador ᴿ cuando retrógrado.
Rotación canónica: Asc a las 9, casas crecen contrarreloj.
- shell: ahora llama engine::compute() real y reporta errores por
stderr sin caer la app.
Datos sintetizados: ascendente, MC, descendente, IC; 12 cusps de
casa según el sistema configurado; placements de los cuerpos del
BodySet con sus longitudes zodiacales, casa y flag retrógrado;
aspectos mayores con opacidad proporcional al orb.
`cargo check` y `cargo test --features eternal-bridge` verdes.
La fase 4 traerá el panel interactivo (jog-dial, toggles, sliders,
atajos teclado).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>