04 · project

Générateur de mandala corrélé à la santé.

Domain: dev Created: 2026-04-29 Updated: 2026-04-29

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 DOM
  • options : 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.

Resources


← All projects