Commit Graph

9 Commits

Author SHA1 Message Date
sergio e0c5c02b8e feat(tahuantinsuyu): fase 8 — slider interactivo + slider de edad en progression
Los `Control::Slider` del panel ya no son display-only — son arrastrables
con el mismo patrón del splitter (canvas absoluto sobre el track + window
mouse handlers en cada frame). El `ProgressionModule` ahora expone un
slider de `target_age_years` (0..120) que el shell inicializa con la
edad actual del sujeto al cargar la carta.

- panel: SliderDrag struct + slider_state HashMap + slider_drag Option
  + métodos start/continue/end_slider_drag + apply_slider_position que
  calcula fraction desde la posición del mouse relativa al track y
  emite ControlChanged con el valor float. set_slider(module, key, val)
  para sincronización externa. set_active_kind ahora inicializa también
  los sliders desde sus defaults. render_slider pinta track + portion
  filled + thumb circular + canvas overlay con handlers de drag.
  Los Slider tienen un valor visible "X.X (min...max)" en el header.
- modules: ProgressionModule agrega Control::Slider target_age_years
  con range 0..120, step 0.25, default 30 (placeholder — el shell lo
  reescribe con la edad real al cargar la carta).
- shell: apply_selection(Chart) ahora calcula current_age, lo inserta
  en module_configs["progression"]["target_age_years"], y empuja al
  panel via set_slider. build_requests ya leía target_age_years desde
  el map (de fase 7), así que ahora el slider lo controla.

Mecánica: si activás "Progresión secundaria", el slider arranca en la
edad actual del sujeto. Arrastralo a la izquierda y la rueda recompone
la carta progresada para esa edad simbólica — vas viendo cómo el sujeto
"evoluciona" o "involuciona" a través de su línea temporal interna,
con los planetas progresados moviéndose por el anillo interno y los
cross aspects con la natal reorganizándose en tiempo real.

Same pattern aplica de aquí en más para cualquier slider futuro
(harmonic en NatalModule, target_year en SolarArc, orb_multiplier, …).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 10:54:06 +00:00
sergio 42e09fd7cd feat(tahuantinsuyu): fase 7 — progresión secundaria como overlay (prueba de la arquitectura)
Valida que el refactor de fase 6 escala: agregar un overlay nuevo
(progresión secundaria, "día por año") tocó exactamente lo predicho —
una variante en PipelineRequest, un helper en bridge, un módulo
declarativo en `progression`, una línea en build_requests, y el canvas
para pintarlo. Cero cambios en el flujo de eventos del Shell.

- engine: PipelineRequest::SecondaryProgression { target_age_years: f64 }
  + build_progression_overlay(natal, age, render) que delega en
  eternal_astrology::secondary_progression(natal, session, age), pinta
  los placements progresados en un anillo interno (ring 0.48), y suma
  cross-aspects natal × progresada vía find_synastry_aspects (sólo
  mayores, opacidad × 0.7). z = 6/7 — sobre las capas natal y
  transit.
- modules: progression::ProgressionModule con id "progression", toggle
  "Activar" (sin hotkey por ahora). Registry::with_builtins lo agrega.
  El test pasó de 2 a 3 módulos para ChartKind::Natal.
- shell: build_requests detecta progression.enabled, calcula la edad
  decimal desde StoredBirthData y SystemTime::now() (current_age_years
  helper, aproximación tropical) y arma el request con esa edad.
  El resto del flujo del shell se mantiene — la abstracción funciona.
- canvas: Radii agrega `progression: r * 0.48`, `aspects` shrunk a
  `r * 0.38` para hacer lugar. Helper aspect_endpoints(module_id)
  resuelve el par (r_from, r_to) según natal/transit/progression.
  paint_wheel pinta dots progresados con alpha 0.85 + anillo guía
  sutil que delimita el slot. Glyph overlay pinta planet symbols en
  el ring de progresión con font_size 14 y box 20 (menores que el
  natal para diferenciar visualmente).

Probarlo: en el panel, activar "Progresión secundaria" — verás los
planetas progresados en un anillo interno con su retrogradación
marcada, y líneas de aspectos que cruzan desde el ring de cuerpos
natales hacia el ring progresivo. Combinable con tránsitos: ambos
overlays apilan capas en orden bodies → transits, sin colisiones.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 10:42:25 +00:00
sergio d4761bf238 refactor(tahuantinsuyu): fase 6 — Modules pluggables vía compose + PipelineRequest
El shell ya no carga el flag `show_transits: bool` ni hardcodea qué
pipeline corre. La engine expone una sola API `compose(chart, offset,
&[PipelineRequest])` que la shell alimenta a partir de un map
`module_configs: HashMap<String, serde_json::Value>`. Los toggles de
overlay (transit hoy, progression/synastry/solar_arc en fase 7) viven
como módulos propios en el panel.

- engine: PipelineRequest enum (variante Transit por ahora; comentarios
  con el roadmap de SecondaryProgression/SolarArc/Synastry). compose()
  es la nueva entrada canónica; compute / compute_at_offset /
  compute_with_transits_at_now quedan como atajos retrocompatibles que
  delegan en compose. bridge.rs refactor: extraído build_transit_overlay
  como helper que muta &mut RenderModel, listo para que más pipelines
  apilen capas encima.
- modules: nuevo módulo `transit::TransitModule` (id "transit", toggle
  "enabled" con hotkey [T], applies_to Natal). Sacado el toggle
  show_transits de NatalModule — ahora cada módulo declara lo suyo.
  Registry::with_builtins() registra ambos. Test asegura los dos
  aplican a Natal.
- panel: sin cambios — ya itera Registry::for_kind(kind) y renderea
  cada módulo aplicable con sus controls. La adición del TransitModule
  aparece automática como segunda card en el panel.
- shell: replace show_transits por module_configs map. build_requests()
  deriva PipelineRequest::Transit cuando module_configs["transit"]
  ["enabled"] == true. on_panel_event: toggles del NatalModule afectan
  solo visibility del canvas; toggles de otros módulos van al
  module_configs y disparan render_current. on_canvas_event: [T]
  hotkey → flip transit.enabled + sync panel + recompose. apps Cargo
  agrega serde_json como dep directa.

Todos los tests verdes. Fase 7 puede sumar overlays adicionales
(progression, solar_arc) solo agregando variantes a PipelineRequest +
helpers en bridge + módulos declarativos — sin tocar el shell.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 10:31:11 +00:00
sergio 4d14a4495f feat(tahuantinsuyu): fase 5 — overlay de tránsitos (bi-wheel natal × ahora)
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>
2026-05-17 10:24:36 +00:00
sergio 360797132e feat(tahuantinsuyu): fase 4 — jog-dial perimetral, hotkeys y panel interactivo
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>
2026-05-17 10:15:09 +00:00
sergio f4944218e2 fix(tahuantinsuyu-engine): leer longitude_rate_rad_per_day directo
`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>
2026-05-16 01:50:48 +00:00
sergio 82fa370877 feat(tahuantinsuyu): fase 3 — engine real contra eternal + rueda pintada en GPUI
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>
2026-05-16 01:43:11 +00:00
sergio bcb92b537e feat(tahuantinsuyu): fase 2 — CRUD UX sobre el tree (menú, modales, form natal)
Right-click sobre el explorador izquierdo abre menú contextual cuyas
opciones dependen del target (raíz, group, contact o chart). Modales
flotantes para crear/renombrar usando yahweh-widget-text-input; un
form más completo de 11 campos para la birth data al crear cartas
natales. Borrar pide confirmación por window.prompt nativo.

- tahuantinsuyu-store: rename_contact, rename_chart, move_group,
  move_contact (los `move_*` para fase posterior de drag-to-nest).
- tahuantinsuyu-tree: estado interno (Menu, Modal enum, ChartForm),
  handlers de ContextMenuRequested, render overlays.
  Soporta seis modales: rename de g/c/h, create group/contact, form
  natal completo con parseo + reporte de errores inline.
  Auto-expande el contact tras crear una carta.
  Nuevo evento TreeEvent::HierarchyChanged tras cada mutación.
- shell: maneja HierarchyChanged sin propagar selección.

`cargo check` y `cargo test` verdes. Fase 3 viene con engine real
contra eternal-astrology + pintado de la rueda.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:13:17 +00:00
sergio c48638fe87 feat(tahuantinsuyu): scaffolding del estudio astrológico (10 crates + ventana 3-panes)
Módulo nuevo `modules/tahuantinsuyu/` con 9 crates reusables + app
`apps/tahuantinsuyu` ejecutable que abre la ventana del explorador y
coordina los widgets:

- tahuantinsuyu-card: Card Brahman + spawn_sidecar (flows
  chart-request/chart-result).
- tahuantinsuyu-model: tipos agnósticos (Group/Contact/Chart,
  StoredBirthData, StoredChartConfig, ChartKind, TreeSelection).
- tahuantinsuyu-store: persistencia SQLite (rusqlite) con migración v1,
  CRUD por entidad y descenso recursivo `charts_under_group`.
- tahuantinsuyu-engine: bridge agnóstico al canvas vía `RenderModel`
  (Layer/Glyph/Geometry). Feature `eternal-bridge` (off por default)
  reservada para enchufar eternal-astrology desde ~/eternal.
- tahuantinsuyu-modules: registry de módulos pluggables (Module trait
  + Control schema) con `NatalModule` placeholder.
- tahuantinsuyu-theme: AstroPalette (elementos / modos / planetas /
  aspectos) con variantes dark + light sobre yahweh-theme.
- tahuantinsuyu-canvas: widget GPUI con CanvasState (Empty / Wheel /
  Thumbnails). Render placeholder hasta cablear la rueda real.
- tahuantinsuyu-tree: explorador izquierdo sobre yahweh-widget-tree,
  prefijos g:/c:/h: para Group/Contact/Chart.
- tahuantinsuyu-panel: control panel inferior que lee Controls de los
  módulos del registry y los pinta.
- apps/tahuantinsuyu: binario `tahuantinsuyu` (launch_app-style) con
  Shell coordinador (tree↔canvas↔panel), DB en $XDG_DATA_HOME.

Workspace Cargo.toml actualizado con los 10 miembros. `cargo check`
verde, tests unitarios verdes (model/store/engine/modules/theme/card).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:06:03 +00:00