Générateur de mandala corrélé à la santé.
Mandala procédural respirant pour la page santé MyLastNight. Chaque chargement génère un mandala unique. Les paramètres reflètent l'état de l'utilisateur en temps réel.
mln-mandala
Mandala procédural respirant pour la page santé MyLastNight.
Chaque chargement génère un mandala unique. Les paramètres reflètent l'état du système en temps réel.
Version : 1.0.0 — 29 avril 2026
Dépendances : aucune (SVG + JS pur, ~280 lignes)
Cible : service identity sur Pi4, servi à tous les subdomains mylastnight.eu
Concept
La carte santé du dashboard affiche un mandala dont la géométrie raconte l'état du système :
| Donnée système | Paramètre mandala | Effet visuel |
|---|---|---|
| Santé globale | health (0–100) |
Pétales plus amples ou plus serrés |
| Humeur déclarée ou dérivée | mood |
Couleur du dégradé radial du fond |
| Stabilité du système | symmetry (6–24) |
Nombre d'axes de symétrie |
| Profondeur de monitoring | layers (3–8) |
Couches concentriques |
| Variabilité métriques | breathing (0–100) |
Amplitude de la respiration |
Mandala = représentation symbolique du système. Pas un graphique, une présence.
Architecture visuelle
Trois principes qui font l'esthétique du mandala :
1. Couches superposées indépendantes
Plusieurs couches concentriques. Chacune a son rayon, sa vitesse de rotation (parfois inverse), sa fréquence et phase de respiration. La géométrie d'ensemble reste cohérente grâce aux axes de symétrie partagés, mais le mouvement n'est jamais "en bloc" — chaque couche vit son propre rythme. Comme les harmoniques d'une corde vibrante.
2. Distribution alternée des formes de pétales
Couche 0 (centre) : ronde et douce. Couche 1 : pointue. Couche 2 : ronde. Etc. Les pétales ronds et pointus se répondent de couche en couche, créant un rythme visuel net, presque comme une broderie ou un vitrail.
3. Respiration multi-fréquence par couche
Trois oscillations indépendantes par couche (rayon, allongement, largeur), chacune à une fréquence légèrement décalée. Aucune des trois n'est en phase avec les autres, ce qui produit un mouvement organique imprévisible mais doux.
Choix techniques
| Choix | Raison |
|---|---|
| SVG natif (pas de Canvas) | Tracé vectoriel net à toute résolution, accessible, indexable |
| Aucune bibliothèque | Pas de dépendance externe à charger ; cohérent avec le service identity |
requestAnimationFrame |
Animation fluide synchronisée avec le rafraîchissement écran |
Pas de filtre feGaussianBlur (glow) |
Performance GPU sur mobile ; tracé blanc pur suffit |
| Seed aléatoire à chaque chargement | Surprise garantie, pas de cache visuel |
Interpolation lerp à 0.06 |
Transitions fluides sur ~1 seconde lors des mises à jour live |
Installation
Place le fichier dans le service identity sur Pi4 :
/home/pi/Dockers/identity/static/mln-mandala.js
Sert depuis tous les subdomains mylastnight.eu au même chemin que mln-base.css, mln-navbar.js, etc.
Référence dans la page santé :
<script src="https://identity.mylastnight.eu/mln-mandala.js"></script>
Usage de base
<div id="mandala-card" style="aspect-ratio: 1; border-radius: 16px; overflow: hidden;"></div>
<script>
const m = MlnMandala.init('#mandala-card', {
health: 75, // amplitude des pétales
mood: 'serene', // couleur du fond
symmetry: 12, // axes de symétrie
layers: 6, // couches concentriques
breathing: 60 // amplitude de respiration
});
</script>
API
MlnMandala.init(container, options)
Crée et démarre un mandala dans le container indiqué.
container: sélecteur CSS ('#id') ou élément DOMoptions: objet de paramètres initiaux (tous optionnels)- retour : instance avec
update(),regenerate(),destroy()
instance.update(newParams)
Met à jour un ou plusieurs paramètres avec interpolation fluide. Les transitions prennent ~1 seconde.
m.update({ health: 40 }); // contraction douce
m.update({ mood: 'melancholic' }); // fond change progressivement
m.update({ health: 80, breathing: 80 }); // plusieurs paramètres d'un coup
Les paramètres health, symmetry, breathing sont interpolés. mood change avec une transition CSS de 1.5s. layers déclenche une régénération complète (changement structurel).
instance.regenerate()
Génère un nouveau mandala avec une nouvelle seed aléatoire. Anime le tracé à l'apparition.
instance.destroy()
Arrête l'animation, retire le SVG du DOM, nettoie le fond du container.
MlnMandala.moods
Liste des humeurs disponibles : ['serene', 'vibrant', 'melancholic', 'warm', 'cool', 'night'].
Mapping métriques → paramètres
Suggestion de règles pour brancher le mandala sur les métriques système. À implémenter côté mln-api ou directement dans la page santé.
health (0–100)
Moyenne pondérée des indicateurs disponibles :
health = 0.30 * cpu_score
+ 0.20 * memory_score
+ 0.20 * services_up_ratio
+ 0.15 * disk_score
+ 0.15 * network_latency_score
Chaque score normalisé de 0 (critique) à 100 (parfait). Pondération ajustable selon ce qui compte le plus dans le contexte MyLastNight.
mood
Règle déclarative en cascade :
| Condition | mood |
|---|---|
| Alerte critique active | vibrant (urgent) |
| Dégradation modérée | warm (attention) |
| Système calme et stable | serene (par défaut) |
| Heure tardive (22h–6h) | night |
| Activité réseau intense | cool |
| Long délai sans incident | melancholic (mélancolie sereine d'un système qui dort) |
Ou simplement un toggle manuel dans le dashboard.
breathing (0–100)
Inversement proportionnel à la stabilité, ou directement proportionnel à la variabilité des métriques :
breathing = clamp(metric_stddev_normalized * 100, 20, 90)
Système calme → mandala respire doucement (~30). Système qui oscille → respiration ample (~70).
symmetry et layers
Plus stables, moins liés au temps réel. Suggestions :
symmetry: refléter le nombre de services actifs (12 par défaut, +2 par service critique en plus)layers: profondeur du monitoring (4 si seul Pi5 monitoré, 6 si Pi4+Pi5, 7+ si stack étendue)
Exemple : alimentation depuis mln-api
const m = MlnMandala.init('#mandala-card', { mood: 'serene' });
async function refreshHealth() {
try {
const r = await fetch('https://mln-api.mylastnight.eu/health');
const data = await r.json();
m.update({
health: data.overallScore,
mood: data.derivedMood,
breathing: data.variabilityScore
});
} catch (e) {
// en cas d'erreur, on bascule en mode "froid"
m.update({ mood: 'cool', health: 30 });
}
}
refreshHealth();
setInterval(refreshHealth, 30000);
Endpoint à implémenter côté mln-api (Flask/Gunicorn sur Pi5, port 5000) :
GET /health
→ {
"overallScore": 78,
"derivedMood": "serene",
"variabilityScore": 45,
"timestamp": "2026-04-29T14:32:00Z"
}
Performance
Mesures indicatives sur un mandala de 6 couches × 12 axes (72 pétales animés) :
| Plateforme | CPU usage | FPS |
|---|---|---|
| MacBook Air M2 (Safari) | ~2% | 60 |
| iPhone 14 (Safari) | ~5% | 60 |
| Pi 4 (Chromium kiosk) | ~12% | 55–60 |
Pour des configurations plus lourdes (16 axes × 8 couches = 128 pétales), prévoir un fallback breathing: 0 sur les appareils faibles.
Évolutions possibles
Pistes pour une v1.1 si le besoin se fait sentir :
- Bruit de Perlin 1D au lieu de
Math.sin()pour les oscillations (mouvement plus organique) - Décalage de phase entre pétales d'une même couche (effet de vague qui circule)
- Couplage faible entre couches voisines (la respiration d'une couche influe légèrement sur la suivante)
- Seed quotidienne optionnelle (
seed: 'daily') pour que le mandala soit reproductible le même jour - Export SVG statique pour archivage ou partage social
Licence
Code interne MyLastNight. Pas de redistribution prévue à ce stade.
Historique des versions
- 1.0.0 (2026-04-29) : version initiale. Distribution alternée, dégradé radial, tracé blanc pur, animation de tracé à l'apparition, API
update()avec interpolation fluide.
Ressources
-
files.zip
5 KB
-
README.md
8 KB
-
README.pdf
189 KB