tawasuyu

tawasuyu/brahman

Rust 570TOML 215Markdown 68JSON 198261 Sutichaykuna

⎇ 1078e433f24ac83e2540343e82d2bd0fe49e304a crates/modules/tahuantinsuyu/tahuantinsuyu-theme/src/lib.rs Rust · 421 siq'ikuna · 14.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat(tahuantinsuyu): rueda 3D, hover-highlight, universo, themes papel 1078e433f · sergio ·

1//! `tahuantinsuyu-theme` — paleta simbólica + presets místicos.
2//!
3//! Una capa fina sobre [`yahweh_theme::Theme`]: el theme base aporta los
4//! slots de panel/foreground/accent; nosotros agregamos paletas
5//! semánticas para los elementos (fuego/tierra/aire/agua), los modos
6//! (cardinal/fijo/mutable), los planetas y los aspectos.
7//!
8//! El canvas pide colores por símbolo (`palette.element(Element::Fire)`),
9//! nunca hex directos. Así una sola tabla controla tanto el dark como el
10//! light, y cambiar la paleta no requiere tocar el render.
11
12#![forbid(unsafe_code)]
13#![warn(rust_2018_idioms)]
14
15use gpui::{Hsla, hsla};
16
17// =====================================================================
18// Símbolos
19// =====================================================================
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum Element {
23    Fire,
24    Earth,
25    Air,
26    Water,
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub enum Modality {
31    Cardinal,
32    Fixed,
33    Mutable,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37pub enum Planet {
38    Sun,
39    Moon,
40    Mercury,
41    Venus,
42    Mars,
43    Jupiter,
44    Saturn,
45    Uranus,
46    Neptune,
47    Pluto,
48    Chiron,
49    NorthNode,
50    SouthNode,
51    Lilith,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
55pub enum AspectKind {
56    Conjunction,
57    Sextile,
58    Square,
59    Trine,
60    Opposition,
61    Quincunx,
62    Semisextile,
63    Semisquare,
64    Sesquisquare,
65    Quintile,
66    Biquintile,
67}
68
69// =====================================================================
70// Paleta
71// =====================================================================
72
73/// Paleta completa de símbolos astrológicos resuelta a colores HSLA. Las
74/// dos variantes (`dark` / `light`) comparten estructura — el canvas
75/// elige según `yahweh_theme::Theme::is_dark`.
76#[derive(Debug, Clone)]
77pub struct AstroPalette {
78    pub is_dark: bool,
79
80    pub fire: Hsla,
81    pub earth: Hsla,
82    pub air: Hsla,
83    pub water: Hsla,
84
85    pub cardinal: Hsla,
86    pub fixed: Hsla,
87    pub mutable: Hsla,
88
89    pub sun: Hsla,
90    pub moon: Hsla,
91    pub mercury: Hsla,
92    pub venus: Hsla,
93    pub mars: Hsla,
94    pub jupiter: Hsla,
95    pub saturn: Hsla,
96    pub uranus: Hsla,
97    pub neptune: Hsla,
98    pub pluto: Hsla,
99    pub chiron: Hsla,
100    pub north_node: Hsla,
101    pub south_node: Hsla,
102    pub lilith: Hsla,
103
104    pub conjunction: Hsla,
105    pub sextile: Hsla,
106    pub square: Hsla,
107    pub trine: Hsla,
108    pub opposition: Hsla,
109    pub minor_aspect: Hsla,
110
111    /// Color del dial zodiacal (anillo exterior).
112    pub dial_ring: Hsla,
113    /// Cusps de casas.
114    pub house_cusp: Hsla,
115    /// Resaltado del ascendente / MC.
116    pub angle_highlight: Hsla,
117}
118
119impl AstroPalette {
120    /// Variante oscura — calibrada para sentirse cálida y mística sin
121    /// caer en saturación de carnaval. Las cusps quedan apenas más
122    /// claras que el fondo, los planetas tienen luminancia media-alta
123    /// para destacar sin glow falso.
124    pub fn dark() -> Self {
125        Self {
126            is_dark: true,
127
128            // Elementos — saturación alta + luminancia media. Familiares
129            // al símbolo pero suaves para coexistir.
130            fire: hsla(11.0 / 360.0, 0.78, 0.58, 1.0),
131            earth: hsla(95.0 / 360.0, 0.40, 0.48, 1.0),
132            air: hsla(48.0 / 360.0, 0.72, 0.66, 1.0),
133            water: hsla(210.0 / 360.0, 0.68, 0.58, 1.0),
134
135            cardinal: hsla(340.0 / 360.0, 0.55, 0.62, 1.0),
136            fixed: hsla(258.0 / 360.0, 0.48, 0.58, 1.0),
137            mutable: hsla(170.0 / 360.0, 0.42, 0.55, 1.0),
138
139            sun: hsla(45.0 / 360.0, 0.92, 0.62, 1.0),
140            moon: hsla(220.0 / 360.0, 0.25, 0.85, 1.0),
141            mercury: hsla(140.0 / 360.0, 0.40, 0.62, 1.0),
142            venus: hsla(330.0 / 360.0, 0.55, 0.70, 1.0),
143            mars: hsla(8.0 / 360.0, 0.78, 0.55, 1.0),
144            jupiter: hsla(38.0 / 360.0, 0.72, 0.62, 1.0),
145            saturn: hsla(28.0 / 360.0, 0.20, 0.50, 1.0),
146            uranus: hsla(195.0 / 360.0, 0.65, 0.62, 1.0),
147            neptune: hsla(225.0 / 360.0, 0.55, 0.66, 1.0),
148            pluto: hsla(280.0 / 360.0, 0.40, 0.45, 1.0),
149            chiron: hsla(75.0 / 360.0, 0.30, 0.55, 1.0),
150            north_node: hsla(35.0 / 360.0, 0.35, 0.70, 1.0),
151            south_node: hsla(35.0 / 360.0, 0.20, 0.45, 1.0),
152            lilith: hsla(310.0 / 360.0, 0.45, 0.40, 1.0),
153
154            conjunction: hsla(50.0 / 360.0, 0.65, 0.70, 0.85),
155            sextile: hsla(195.0 / 360.0, 0.60, 0.62, 0.75),
156            square: hsla(8.0 / 360.0, 0.75, 0.58, 0.85),
157            trine: hsla(140.0 / 360.0, 0.55, 0.55, 0.80),
158            opposition: hsla(280.0 / 360.0, 0.55, 0.62, 0.85),
159            minor_aspect: hsla(220.0 / 360.0, 0.20, 0.55, 0.55),
160
161            dial_ring: hsla(40.0 / 360.0, 0.18, 0.78, 0.85),
162            house_cusp: hsla(40.0 / 360.0, 0.12, 0.55, 0.60),
163            angle_highlight: hsla(50.0 / 360.0, 0.95, 0.65, 1.0),
164        }
165    }
166
167    /// Variante clara — desaturada y con luminancias bajas para que los
168    /// símbolos no compitan con el fondo blanco. Pensada para imprimir.
169    pub fn light() -> Self {
170        Self {
171            is_dark: false,
172
173            fire: hsla(11.0 / 360.0, 0.65, 0.42, 1.0),
174            earth: hsla(95.0 / 360.0, 0.45, 0.30, 1.0),
175            air: hsla(48.0 / 360.0, 0.55, 0.42, 1.0),
176            water: hsla(210.0 / 360.0, 0.60, 0.38, 1.0),
177
178            cardinal: hsla(340.0 / 360.0, 0.55, 0.42, 1.0),
179            fixed: hsla(258.0 / 360.0, 0.45, 0.40, 1.0),
180            mutable: hsla(170.0 / 360.0, 0.42, 0.35, 1.0),
181
182            sun: hsla(38.0 / 360.0, 0.85, 0.45, 1.0),
183            moon: hsla(220.0 / 360.0, 0.22, 0.45, 1.0),
184            mercury: hsla(140.0 / 360.0, 0.45, 0.36, 1.0),
185            venus: hsla(330.0 / 360.0, 0.55, 0.45, 1.0),
186            mars: hsla(8.0 / 360.0, 0.75, 0.40, 1.0),
187            jupiter: hsla(38.0 / 360.0, 0.72, 0.42, 1.0),
188            saturn: hsla(28.0 / 360.0, 0.25, 0.30, 1.0),
189            uranus: hsla(195.0 / 360.0, 0.65, 0.40, 1.0),
190            neptune: hsla(225.0 / 360.0, 0.55, 0.42, 1.0),
191            pluto: hsla(280.0 / 360.0, 0.45, 0.30, 1.0),
192            chiron: hsla(75.0 / 360.0, 0.32, 0.35, 1.0),
193            north_node: hsla(35.0 / 360.0, 0.45, 0.45, 1.0),
194            south_node: hsla(35.0 / 360.0, 0.20, 0.30, 1.0),
195            lilith: hsla(310.0 / 360.0, 0.50, 0.30, 1.0),
196
197            // Aspectos en light: alpha alta y luminancia media-baja para
198            // que las líneas tengan presencia contra fondo claro. En dark
199            // las alphas pueden ser más bajas porque el contraste contra
200            // el fondo oscuro ya las hace destacar.
201            conjunction: hsla(45.0 / 360.0, 0.70, 0.38, 0.95),
202            sextile: hsla(195.0 / 360.0, 0.65, 0.36, 0.90),
203            square: hsla(8.0 / 360.0, 0.80, 0.38, 0.95),
204            trine: hsla(140.0 / 360.0, 0.60, 0.32, 0.92),
205            opposition: hsla(280.0 / 360.0, 0.60, 0.40, 0.95),
206            minor_aspect: hsla(220.0 / 360.0, 0.30, 0.38, 0.75),
207
208            // dial_ring: luminancia baja (oscuro sobre blanco) para que
209            // el anillo de signos tenga peso. house_cusp: subimos alpha
210            // y bajamos luminancia para que las cúspides no se laven en
211            // un beige translúcido.
212            dial_ring: hsla(40.0 / 360.0, 0.20, 0.28, 0.95),
213            house_cusp: hsla(40.0 / 360.0, 0.15, 0.32, 0.80),
214            angle_highlight: hsla(38.0 / 360.0, 0.90, 0.38, 1.0),
215        }
216    }
217
218    /// Variante "papel coloreado" — para preview de impresión. Hue de
219    /// cada slot mantenido; luminancia 0.26-0.34 y saturación alta
220    /// para que sobreviva el ink-bleed sin perder identidad. Sin glow.
221    pub fn print_color() -> Self {
222        Self {
223            is_dark: false,
224
225            fire: hsla(11.0 / 360.0, 0.78, 0.34, 1.0),
226            earth: hsla(95.0 / 360.0, 0.55, 0.26, 1.0),
227            air: hsla(48.0 / 360.0, 0.78, 0.34, 1.0),
228            water: hsla(210.0 / 360.0, 0.72, 0.32, 1.0),
229
230            cardinal: hsla(340.0 / 360.0, 0.65, 0.34, 1.0),
231            fixed: hsla(258.0 / 360.0, 0.55, 0.32, 1.0),
232            mutable: hsla(170.0 / 360.0, 0.55, 0.28, 1.0),
233
234            sun: hsla(35.0 / 360.0, 0.95, 0.34, 1.0),
235            moon: hsla(220.0 / 360.0, 0.35, 0.34, 1.0),
236            mercury: hsla(140.0 / 360.0, 0.55, 0.28, 1.0),
237            venus: hsla(330.0 / 360.0, 0.65, 0.36, 1.0),
238            mars: hsla(8.0 / 360.0, 0.85, 0.34, 1.0),
239            jupiter: hsla(38.0 / 360.0, 0.85, 0.34, 1.0),
240            saturn: hsla(28.0 / 360.0, 0.30, 0.26, 1.0),
241            uranus: hsla(195.0 / 360.0, 0.75, 0.34, 1.0),
242            neptune: hsla(225.0 / 360.0, 0.65, 0.34, 1.0),
243            pluto: hsla(280.0 / 360.0, 0.55, 0.28, 1.0),
244            chiron: hsla(75.0 / 360.0, 0.42, 0.30, 1.0),
245            north_node: hsla(35.0 / 360.0, 0.55, 0.36, 1.0),
246            south_node: hsla(35.0 / 360.0, 0.30, 0.28, 1.0),
247            lilith: hsla(310.0 / 360.0, 0.60, 0.26, 1.0),
248
249            conjunction: hsla(45.0 / 360.0, 0.75, 0.32, 1.0),
250            sextile: hsla(195.0 / 360.0, 0.70, 0.32, 1.0),
251            square: hsla(8.0 / 360.0, 0.85, 0.34, 1.0),
252            trine: hsla(140.0 / 360.0, 0.65, 0.28, 1.0),
253            opposition: hsla(280.0 / 360.0, 0.65, 0.36, 1.0),
254            minor_aspect: hsla(220.0 / 360.0, 0.40, 0.40, 0.85),
255
256            dial_ring: hsla(40.0 / 360.0, 0.30, 0.22, 1.0),
257            house_cusp: hsla(40.0 / 360.0, 0.20, 0.28, 0.90),
258            angle_highlight: hsla(15.0 / 360.0, 0.85, 0.36, 1.0),
259        }
260    }
261
262    /// Variante "papel B&N" — preview de impresión monocromática.
263    /// TODO los slots de planeta y aspecto se reducen a niveles de
264    /// gris. El canvas se encarga de diferenciar aspectos por dash
265    /// pattern y planetas por glyph (el unicode astronómico es
266    /// distintivo aunque pierda color).
267    pub fn print_bw() -> Self {
268        // Tres niveles funcionales: muy oscuro (texto, glyphs
269        // principales), medio (cusps, líneas), claro (fondos, minors).
270        let ink_strong = hsla(0.0, 0.0, 0.10, 1.0);
271        let ink_mid = hsla(0.0, 0.0, 0.30, 1.0);
272        let ink_soft = hsla(0.0, 0.0, 0.50, 0.90);
273        let ink_faint = hsla(0.0, 0.0, 0.55, 0.75);
274
275        Self {
276            is_dark: false,
277
278            fire: ink_strong,
279            earth: ink_strong,
280            air: ink_strong,
281            water: ink_strong,
282
283            cardinal: ink_mid,
284            fixed: ink_mid,
285            mutable: ink_mid,
286
287            // Planetas: todos en ink_strong para que los glyphs se
288            // lean fuerte. El usuario distingue por el unicode
289            // astronómico, no por hue.
290            sun: ink_strong,
291            moon: ink_strong,
292            mercury: ink_strong,
293            venus: ink_strong,
294            mars: ink_strong,
295            jupiter: ink_strong,
296            saturn: ink_strong,
297            uranus: ink_strong,
298            neptune: ink_strong,
299            pluto: ink_strong,
300            chiron: ink_mid,
301            north_node: ink_mid,
302            south_node: ink_mid,
303            lilith: ink_mid,
304
305            // Aspectos: el color es uniforme; la diferenciación es por
306            // dash pattern en el painter (square=dashed, trine=solid,
307            // sextile=dotted, etc.). Acá solo damos el "intensity"
308            // base que el painter modula.
309            conjunction: ink_strong,
310            sextile: ink_mid,
311            square: ink_strong,
312            trine: ink_mid,
313            opposition: ink_strong,
314            minor_aspect: ink_faint,
315
316            dial_ring: ink_mid,
317            house_cusp: ink_soft,
318            angle_highlight: ink_strong,
319        }
320    }
321
322    pub fn for_theme(theme: &yahweh_theme::Theme) -> Self {
323        // Dispatcher por nombre para los themes "papel"; el resto cae
324        // al binary dark/light según `is_dark`. Mantenemos el match
325        // case-insensitive por defensa contra cambios de naming.
326        match theme.name {
327            "Print Color" => Self::print_color(),
328            "Print B&W" => Self::print_bw(),
329            _ if theme.is_dark => Self::dark(),
330            _ => Self::light(),
331        }
332    }
333
334    /// Devuelve `true` si la paleta es monocromática — los painters
335    /// la usan para activar dash patterns en lugar de diferenciar
336    /// aspectos por color.
337    pub fn is_monochrome(&self) -> bool {
338        // Heurística simple: si conjunction y square (que en color
339        // siempre tienen hues distintos) tienen el mismo hue,
340        // estamos en BW.
341        (self.conjunction.h - self.square.h).abs() < 1e-3
342    }
343
344    pub fn element(&self, e: Element) -> Hsla {
345        match e {
346            Element::Fire => self.fire,
347            Element::Earth => self.earth,
348            Element::Air => self.air,
349            Element::Water => self.water,
350        }
351    }
352
353    pub fn modality(&self, m: Modality) -> Hsla {
354        match m {
355            Modality::Cardinal => self.cardinal,
356            Modality::Fixed => self.fixed,
357            Modality::Mutable => self.mutable,
358        }
359    }
360
361    pub fn planet(&self, p: Planet) -> Hsla {
362        match p {
363            Planet::Sun => self.sun,
364            Planet::Moon => self.moon,
365            Planet::Mercury => self.mercury,
366            Planet::Venus => self.venus,
367            Planet::Mars => self.mars,
368            Planet::Jupiter => self.jupiter,
369            Planet::Saturn => self.saturn,
370            Planet::Uranus => self.uranus,
371            Planet::Neptune => self.neptune,
372            Planet::Pluto => self.pluto,
373            Planet::Chiron => self.chiron,
374            Planet::NorthNode => self.north_node,
375            Planet::SouthNode => self.south_node,
376            Planet::Lilith => self.lilith,
377        }
378    }
379
380    pub fn aspect(&self, a: AspectKind) -> Hsla {
381        match a {
382            AspectKind::Conjunction => self.conjunction,
383            AspectKind::Sextile => self.sextile,
384            AspectKind::Square => self.square,
385            AspectKind::Trine => self.trine,
386            AspectKind::Opposition => self.opposition,
387            _ => self.minor_aspect,
388        }
389    }
390}
391
392/// Resuelve un símbolo zodiacal (string) a su elemento.
393/// Ej. `"aries" → Fire`, `"taurus" → Earth`, …
394pub fn element_for_sign(sign: &str) -> Option<Element> {
395    Some(match sign.to_ascii_lowercase().as_str() {
396        "aries" | "leo" | "sagittarius" => Element::Fire,
397        "taurus" | "virgo" | "capricorn" => Element::Earth,
398        "gemini" | "libra" | "aquarius" => Element::Air,
399        "cancer" | "scorpio" | "pisces" => Element::Water,
400        _ => return None,
401    })
402}
403
404#[cfg(test)]
405mod tests {
406    use super::*;
407
408    #[test]
409    fn element_lookup() {
410        assert_eq!(element_for_sign("aries"), Some(Element::Fire));
411        assert_eq!(element_for_sign("CAPRICORN"), Some(Element::Earth));
412        assert_eq!(element_for_sign("zod"), None);
413    }
414
415    #[test]
416    fn palette_indexes() {
417        let p = AstroPalette::dark();
418        assert_eq!(p.planet(Planet::Sun), p.sun);
419        assert_eq!(p.element(Element::Water), p.water);
420    }
421}