Bouton IA nébuleuse animé en React Native à l'IA avec des particules
Un bon bouton donne envie d'être pressé. Le bouton IA de TAMSIV est une nébuleuse vivante qui invite à la conversation. Ce n'est pas juste un cercle avec un micro : c'est 8 particules lumineuses qui dansent, respirent et réagissent en temps réel à chaque interaction.
Ce bouton est probablement l'élément de l'interface sur lequel j'ai passé le plus de temps par pixel. Pas parce que c'est le plus important fonctionnellement, mais parce que c'est le premier point de contact entre l'utilisateur et l'intelligence artificielle. Si ce bouton ne donne pas envie de parler, tout le reste ne sert à rien.
Points clés
- Le bouton nébuleuse utilise 8 particules animées via l'Animated API native de React Native, sans Lottie ni Skia, pour un contrôle total sur chaque frame.
- 4 états distincts (inactif, écoute, traitement, réponse) avec des transitions en
Animated.springpour un mouvement organique.- Performance garantie à 60fps même sur des appareils 3 Go de RAM grâce à
useNativeDriveret zéro re-render React.- Le rythme à l'état inactif imite une respiration calme (~4 secondes par cycle), créant un effet de présence vivante.
Pourquoi investir autant de temps sur un simple bouton ?
La réponse courte : parce que c'est le premier contact avec l'IA. La réponse longue implique de la psychologie, du design et de la performance mobile.
Selon les recherches de l'Interaction Design Foundation, les utilisateurs se forment une impression d'une interface en 50 millisecondes. Pas le temps de lire un tutoriel. Pas le temps de comprendre la proposition de valeur. 50ms pour décider si l'app est "pro" ou "amateur".
Le bouton IA de TAMSIV est l'élément le plus visible de l'écran principal. C'est le seul composant qui bouge quand tout le reste est statique. Il doit communiquer trois choses sans un seul mot : "je suis là", "je suis prête", "parle-moi". Si tu dois expliquer à l'utilisateur comment utiliser un bouton, le design a échoué.
J'ai exploré plusieurs pistes avant d'arriver à la nébuleuse. Un simple cercle pulsant, trop générique. Un micro animé, trop littéral. Une onde sonore, trop technique. La nébuleuse est née d'une observation : les nuages cosmiques semblent vivants sans être menaçants. Ils attirent le regard sans agresser. C'est exactement l'émotion que je voulais pour le bouton IA.
Comment fonctionne l'architecture technique de l'effet nébuleuse ?
Le choix technique le plus important a été de refuser les raccourcis. Pas de Lottie (animations pré-rendues), pas de Skia (canvas 2D). Entièrement sur l'Animated API native de React Native. Pourquoi ? Parce que les 4 états du bouton doivent se mélanger dynamiquement. Une animation Lottie est figée : elle joue un fichier de A à Z. L'état nébuleuse doit réagir en temps réel.
L'architecture repose sur 8 cercles flous (blurRadius) qui se déplacent en sinusoïdes. Chaque cercle a trois paramètres indépendants :
- Position : mouvement sinusoïdal en X et Y avec des fréquences légèrement différentes, créant des trajectoires en forme de 8 (figures de Lissajous).
- Opacité : oscillation entre 0.3 et 0.8 pour créer des zones de densité lumineuse variable.
- Échelle : variation subtile entre 0.8 et 1.2 pour simuler la profondeur.
Le mélange de ces 8 cercles crée des zones de concentration lumineuse qui apparaissent et disparaissent naturellement, exactement comme une nébuleuse réelle. Le système de couleurs reste entre le bleu accent de TAMSIV (#137fec) et un violet doux, cohérent avec le thème sombre de l'app (#101922).
Quels sont les 4 états du bouton et comment transitionnent-ils ?
Chaque état modifie les paramètres des 8 particules de manière progressive, jamais brusque. Les transitions utilisent Animated.spring au lieu de Animated.timing pour un feeling organique : le spring génère un léger overshoot naturel que le timing linéaire ne peut pas reproduire.
État inactif : la respiration
Les particules se déplacent lentement. L'amplitude du mouvement est faible. La luminosité est modérée. Le cycle complet dure environ 4 secondes, ce qui correspond au rythme respiratoire calme d'un être humain au repos. Ce n'est pas un hasard : selon les études de Respiratory Research, le rythme respiratoire moyen au repos est de 12-20 cycles par minute, soit 3 à 5 secondes par cycle. En calquant l'animation sur ce rythme, le bouton active inconsciemment un sentiment de calme et de confiance.
État écoute : l'attention
L'utilisateur appuie et parle. L'amplitude des particules augmente de 50%. La luminosité monte. Les particules s'éloignent légèrement du centre, comme si le bouton "ouvrait les oreilles". La transition se fait en spring avec un stiffness élevé pour une réaction immédiate au toucher.
État traitement : la convergence
L'utilisateur relâche. L'IA traite la requête. Les particules convergent vers le centre et la rotation s'accélère. L'effet visuel évoque un tourbillon qui "digère" l'information. C'est un feedback crucial : l'utilisateur sait que sa demande est en cours de traitement sans avoir besoin d'un spinner ou d'un texte "Chargement...".
État réponse : la pulsation audio
Le TTS joue la réponse de l'IA. Les particules pulsent en synchronisation avec l'amplitude audio. Plus le volume est élevé, plus l'amplitude des particules est grande. C'est le même principe que les visualiseurs audio de Spotify ou Apple Music, adapté à un bouton de 60x60 points. J'avais détaillé le pipeline audio complet dans l'article sur le pipeline vocal.
Comment garantir 60fps sur des appareils d'entrée de gamme ?
Animer 8 particules avec position, opacité et échelle, ça fait 24 valeurs animées simultanées. Sur un flagship, c'est trivial. Sur un appareil avec 3 Go de RAM et un processeur Snapdragon 400, c'est un défi sérieux.
La règle numéro 1 : useNativeDriver: true sur chaque animation. Quand le native driver est activé, l'animation est entièrement gérée par le thread natif (UI thread), pas par le bridge JavaScript. Le thread JS est libre pour gérer la logique métier (enregistrement audio, envoi WebSocket, parsing de la réponse IA). Selon la documentation React Native, le native driver peut améliorer les performances d'animation de 60% en moyenne.
La règle numéro 2 : zéro re-render React. Les valeurs animées sont des Animated.Value qui mutent sans déclencher de reconciliation React. Le composant ne se re-render jamais pendant l'animation. Pas de setState, pas de changement de props animées via le state.
La règle numéro 3 : les propriétés animées sont exclusivement des transform (translateX, translateY, scale) et opacity. Ces propriétés sont accélérées par le GPU sur Android et iOS. Pas de width/height/backgroundColor animés, qui nécessiteraient un recalcul de layout à chaque frame.
Résultat : 60fps constant même sur des appareils d'entrée de gamme testés. J'ai initialement commencé avec 16 particules avant de réduire à 8 sans perte visuelle perceptible. C'est un compromis classique en développement mobile que j'applique aussi dans le dictaphone vocal et l'interface inline.
Quel rôle joue la psychologie du mouvement dans le design ?
Le mouvement en UI n'est pas décoratif. Il est informatif. Chaque animation doit répondre à une question implicite de l'utilisateur :
- État inactif : "L'IA est-elle disponible ?" Oui, regarde, elle respire. Elle t'attend.
- État écoute : "M'entend-elle ?" Oui, regarde, elle réagit à ta voix.
- État traitement : "Ma demande est-elle prise en compte ?" Oui, regarde, elle travaille.
- État réponse : "Est-ce l'IA qui parle ?" Oui, regarde, elle pulse avec l'audio.
Le Disney Animation Studio a formalisé ce principe dans ses 12 principes fondamentaux de l'animation. Deux sont particulièrement pertinents ici : "anticipation" (le bouton se prépare avant d'agir) et "follow through" (le bouton continue de réagir après l'action).
Le retour le plus gratifiant des testeurs a été : "On dirait qu'elle attend que je lui parle." Ce n'est pas un compliment sur l'animation. C'est un compliment sur l'émotion. L'animation a réussi à créer une sensation de présence. Et la présence, c'est ce qui transforme un outil en compagnon. J'avais expliqué cette philosophie dans l'article sur la personnalisation vocale : l'IA ne doit pas juste être utile, elle doit être agréable.
Pourquoi ne pas utiliser Lottie ou Rive pour ce type d'animation ?
La question est légitime. Lottie est la solution standard pour les animations complexes en mobile. Rive (ex-Flare) est son concurrent plus performant. Les deux auraient pu créer un effet nébuleuse impressionnant. Mais avec une limitation critique : les animations sont pré-calculées.
Le bouton IA de TAMSIV a des états dynamiques qui dépendent de données en temps réel. L'état "réponse" synchronise l'amplitude des particules avec le volume audio du TTS. Ce volume change 60 fois par seconde. Une animation Lottie ne peut pas s'adapter à un flux audio en temps réel : elle joue une séquence fixe.
L'Animated API native offre un contrôle frame-par-frame. Je peux modifier n'importe quel paramètre à n'importe quel moment sans recharger une animation. C'est plus de travail à coder, mais le résultat est plus vivant. C'est la même logique que dans le feed et la gamification : les animations réactives aux données sont toujours plus engageantes que les animations figées.
Comment le bouton s'adapte-t-il au thème et aux couleurs de l'app ?
Le bouton nébuleuse n'existe pas en isolation. Il fait partie d'un design system cohérent avec le thème sombre de TAMSIV : fond #101922, accent #137fec, texte secondaire #9ca3af.
Les particules utilisent un dégradé entre le bleu accent et un violet (#8b5cf6). Ce choix n'est pas esthétique : il est fonctionnel. Le bleu est la couleur d'accent de toute l'interface, les boutons, les liens, les indicateurs. Le violet est utilisé uniquement pour l'IA. Cette distinction chromatique permet à l'utilisateur d'identifier instantanément les éléments liés à l'intelligence artificielle sans lire de texte.
Sur fond sombre, les particules lumineuses créent un contraste naturel sans avoir besoin de bordures ou d'ombres. C'est un principe clé du design dark mode : la lumière devient l'outil de mise en valeur, pas les lignes. J'avais appliqué le même principe dans la recherche contextuelle avec swipe et dans l'onboarding lazy registration.
Questions fréquentes
Le bouton nébuleuse consomme-t-il beaucoup de batterie ?
Non. Les animations utilisent exclusivement le native driver et des propriétés GPU-accélérées (transform, opacity). L'impact batterie est comparable à une animation CSS standard sur le web. Les particules ne tournent pas quand l'app est en arrière-plan.
L'effet fonctionne-t-il différemment sur iOS et Android ?
L'effet visuel est identique sur les deux plateformes grâce à l'Animated API qui abstrait les différences. La seule variation est le blur : iOS utilise un blur natif plus performant, Android utilise un workaround avec opacity réduite qui donne un résultat visuellement similaire.
Peut-on personnaliser les couleurs du bouton ?
Actuellement non. Les couleurs sont liées au design system de TAMSIV. Une personnalisation par thème est envisageable à l'avenir, mais elle nécessiterait de repenser la palette IA pour chaque variation de couleur.
Pourquoi 8 particules et pas plus ?
J'ai testé de 4 à 16 particules. En dessous de 6, l'effet perd sa richesse. Au-dessus de 10, le gain visuel est négligeable mais le coût en performance augmente. 8 est le sweet spot testé sur des appareils allant du Samsung Galaxy A13 au Pixel 8 Pro.
Le bouton est-il accessible aux utilisateurs malvoyants ?
Oui. Le composant inclut un accessibilityLabel descriptif et un accessibilityHint qui indique l'état courant. Les lecteurs d'écran annoncent "Bouton IA, prêt à écouter" ou "Bouton IA, traitement en cours" selon l'état.