la méthode
Une description formelle du moteur de croissance : d'un jeu de données tabulaire à un organisme rendu à l'écran. Toutes les créatures partagent ce pipeline ; seule l'attribution des données change d'une espèce à l'autre.
Le système est un modèle génératif déterministe. Soit en entrée une suite ordonnée d'enregistrements r0, r1, …, rN−1, chacun portant un horodatage et un ou plusieurs champs mesurés. La croissance se déroule en N étapes discrètes ; l'étape i consomme l'enregistrement ri et ajoute un sommet à un ensemble de branches en croissance. Le dessin est entièrement déterminé par les données et par un hachage pseudo-aléatoire fixe, si bien qu'un même jeu de données donne toujours le même organisme. Le canevas mesure W×H = 720×560 avec une marge m = 30.
Chaque enregistrement est réduit à quatre canaux scalaires et à un indicateur de choc. L'attribution des champs sources aux canaux est la seule chose qui varie selon l'espèce ; elle privilégie un champ directionnel réellement mesuré pour θ plutôt qu'un substitut dérivé du calendrier.
Les canaux continus sont normalisés par une mise à l'échelle min–max sur l'ensemble des données, les valeurs étant bornées à une bande de percentiles robuste (typiquement 1er–99e) afin qu'une seule valeur aberrante ne puisse dominer :
Le modèle vise une plage lisible d'environ 400 ≤ N ≤ 1300 étapes. Soit R le nombre de lignes exploitables. L'agrégation est choisie en conséquence :
La croissance n'est pas un marcheur unique mais un ensemble de pointes actives, chacune étant une branche dotée d'une position p = (x, y) et d'un cap α. À chaque étape, chaque pointe avance une fois. Le cap est mis à jour en additionnant plusieurs termes angulaires : une poussée directionnelle issue des données, une faible correction phototropique, un bruit déterministe et (selon l'espèce) de petits termes de dérive. Le couplage exact diffère d'une espèce à l'autre, puisque le champ directionnel diffère ; la forme générale de la mise à jour est
δdir est la poussée angulaire pilotée par les données, ρ le gain phototropique, ηi le bruit. Exemple concret : Datum ventosa convertit la direction du vent en poussée par un sinus, δdir = 0.8·sin((r − 90°)), et utilise ρ = 0.22 ; une autre espèce y substitue sa propre attribution.
Le terme phototropique empêche l'organisme de s'enrouler sur lui-même. Il est calculé par rapport à un centroïde courant (cx, cy), la moyenne de tous les sommets placés jusque-là, mise à jour de façon incrémentale après chaque étape. Soit φ = atan2(y − cy, x − cx) l'angle sortant depuis le centroïde ; la correction Δphoto est la différence, ramenée dans l'intervalle, entre φ et le cap actuel, ce qui pousse la pointe vers l'extérieur :
La longueur de pas convertit un canal d'énergie en pixels, si = s0 + ℓi·Δs, et la pointe avance de (sicosα′, sisinα′).
L'ensemble des pointes est dynamique. Un choc peut faire naître une branche fille selon un angle décalé, jusqu'à un plafond (par ex. 14 pointes simultanées), de sorte que l'organisme se divise là où les données ont connu un pic. À l'inverse, les pointes faibles sont élaguées : une pointe est supprimée avec une probabilité qui augmente à mesure que son canal de masse baisse et que sa génération de branche s'approfondit, pour autant qu'il reste plus de quelques pointes. Si toutes les pointes meurent, une nouvelle est semée au centroïde.
La ramification comme l'élagage tirent leurs décisions du hachage déterministe du §8, si bien que la topologie est reproductible.
Aucun sommet ni point de contrôle ne peut quitter le cadre. La règle canonique, utilisée par la plupart des espèces, réfléchit le cap lorsqu'une pointe proposée franchirait une marge, puis recalcule la position :
Certains spécimens utilisent une variante plus douce, qui détourne le vecteur de cap de la paroi à l'approche de la marge au lieu de le réfléchir ; l'effet visible est le même. Dans tous les cas, deux garanties strictes en découlent : chaque pointe est bornée à [m, W−m]×[m, H−m], chaque point de contrôle de Bézier (§6) est borné de la même façon pour que la courbe ne puisse pas déborder, et un rectangle clip() appliqué à chaque image sert de dernier garde-fou.
Une branche est une polyligne de sommets pk. Des segments droits paraîtraient mécaniques, c'est pourquoi chaque segment pk → pk+1 est rendu comme une Bézier cubique dont les points de contrôle sont des tangentes de type Catmull–Rom, estimées à partir des voisins pk−1 et pk+2 (bornés aux extrémités) :
Le facteur 1/6 correspond à la tangente uniforme de Catmull–Rom. Il s'agit de la paramétrisation uniforme (ni par cordes ni centripète), et les tangentes ne sont pas normalisées par longueur d'arc, ce qui est acceptable ici puisque l'espacement des sommets est déjà borné par le §3.
À gauche : les sommets bruts reliés par de simples segments droits. À droite : les mêmes sommets en chaîne de Bézier de continuité C¹, avec les deux poignées de contrôle d'un segment.
La largeur du trait s'amincit de la base vers la pointe, diminue avec la génération de branche g, et gonfle avec le canal de masse ; un choc ajoute une cicatrice proportionnelle à sa gravité ν:
La couleur est calculée en HSL puis convertie en RGB. Point essentiel, deux axes orthogonaux sont encodés : la teinte porte le champ de données couleur, la luminosité porte l'âge (vieille croissance sombre, jeune croissance claire), si bien que le temps et la donnée couleur ne se percutent jamais. La saturation est fixée à mi-plage ; un choc sature complètement et éclaircit :
La conversion HSL→RGB est la transformation standard par morceaux, avec la chroma C = (1 − |2L − 1|)·S, X = C·(1 − |(H/60) mod 2 − 1|) et le décalage m = L − C/2.
Tout le « hasard » est un hachage reproductible de l'indice d'étape, si bien qu'un organisme est identique à chaque exécution et sur chaque machine. Pas d'état de PRNG, pas de dérive de graine :
Le hachage sinusoïdal classique. Le terme de bruit ηi du §3 et la variation aléatoire des ramifications puisent tous deux dans cette fonction, indexée sur les indices d'étape et de branche.
Un choc est le franchissement d'un seuil dans un champ choisi, typiquement le 95e percentile du canal d'énergie ou de choc, ou une borne propre au domaine (une norme de tempête, une limite de krach, un ratio de surmortalité). Sa gravité ν ∈ [0,1] règle l'ampleur de la cicatrice (§7) et d'une lueur radiale chaude dessinée sous le trait en composition additive, de sorte que la ligne reste nette tandis que le halo s'estompe au cours des 40 étapes suivantes :
La lueur est rendue sous les branches avec globalCompositeOperation = "lighter" ; le trait est dessiné ensuite en source-over, ce qui garde les bords nets.
L'image finale est traitée comme une impression et doit rester propre ; la mort n'entraîne donc aucun effet sur l'ensemble de l'image. Chaque pointe de branche reçoit un point flétri dans la couleur de la mort, et la dernière étape est un moignon raccourci plutôt qu'une pousse complète, signalant que la croissance a été interrompue, pas achevée :
Pour une créature née d'un jeu de données figé, la date de la mort est l'horodatage du dernier enregistrement. Comme le créateur choisit quand exporter les données, le créateur choisit le moment de la mort. C'est le cœur conceptuel, porté par une mention sous le canevas plutôt que par une quelconque altération de l'image.
Deux créatures, la sismique et celle nourrie de pluie, ne naissent pas d'un fichier figé mais d'une source ouverte qui continue de croître. Elles partagent tout le rendu et le lecteur décrits plus haut ; seule la couche de données diffère, et cette différence est voulue.
La mort n'est plus fixée par le créateur. Une créature vivante est en vie tant que sa source continue de la nourrir, et meurt quand le flux se tait. Le test est une propriété des données, pas de la connexion réseau : on calcule l'intervalle médian entre deux relevés consécutifs (la médiane, pas la moyenne, pour résister aux lacunes), on mesure l'âge du relevé le plus récent, et on ne déclare la mort que lorsque cet âge dépasse trois fois l'intervalle médian. Le facteur trois est un seuil de battement de cœur, assez long pour ignorer un relevé manqué, assez court pour détecter un véritable arrêt, et il s'adapte de lui-même à la source : un flux quotidien meurt après environ trois jours de silence, un flux mensuel après environ trois mois.
Le test s'exécute avant la première image, de sorte que la créature s'ouvre dans le bon état au lieu de clignoter de morte à vivante. Tant qu'elle est en vie, le statut affiche en vie · nourri le <date> et la créature pousse jusqu'à sa pleine longueur, sans points flétris ni moignon ; la grammaire de la mort du §10 n'apparaît qu'une fois le test échoué.
Pour rester un seul fichier autonome tout en dépendant d'une source vivante, chaque spécimen vivant est un hybride. Il intègre une souche historique complète avec son propre analyseur, exactement comme une créature morte. À l'ouverture, il lance un fetch() vers la source ouverte (USGS pour les séismes, Open-Meteo pour la météo, toutes deux compatibles CORS et sans clé), récupère chaque relevé depuis la limite de la souche, et continue de pousser jusqu'à aujourd'hui. Si la requête échoue, hors ligne ou parce que la source a changé d'adresse, il se rabat silencieusement sur la souche intégrée.
Une réserve honnête, que l'œuvre énonce clairement : la souche intégrée des deux spécimens vivants est actuellement synthétique, fidèle dans sa structure mais inventée, parce que l'environnement de construction n'avait pas d'accès ouvert à internet pour récupérer l'historique réel. La couche en direct corrige cela dès que le fichier est ouvert en ligne, en poussant sur des données authentiques à partir de la limite de la souche ; mais l'historique montré avant cette limite est plausible, pas mesuré.