Coulisses techniques
Même seed, même vidéo, image par image : le déterminisme du rendu
Pourquoi MotionMaker interdit Math.random au rendu, comment le seed pilote chaque variation et comment la grille rythmique cale montage et son.
Un film généré qu’on ne peut pas reproduire est un film qu’on ne peut pas corriger. Si un défaut apparaît à la quarantième image, il faut pouvoir relancer exactement la même vidéo, pas une cousine. Cet article explique comment MotionMaker rend ses films déterministes : un même seed redonne la même vidéo, image par image. Il décrit aussi le revers de la médaille, c’est-à-dire comment deux générations restent, elles, différentes.
Le problème : l’aléatoire est l’ennemi du débogage
Une vidéo animée se calcule image après image. À 30 images par seconde, un film de 17 secondes en compte 516. Chaque image doit être cohérente avec celle d’avant : une particule qui tremble, une variation de composition tirée « au hasard » à chaque calcul, et le film change d’un rendu à l’autre. Pire : le rendu s’exécute avec plusieurs processus en parallèle (deux, dans notre configuration serveur), si bien que les images ne sont pas forcément calculées dans l’ordre où on les regarde.
Si une image dépend de ce qui a été calculé avant elle, ou d’un tirage aléatoire propre à l’exécution, le rendu parallèle produit des films légèrement différents selon le jour. On ne peut alors plus comparer deux versions, ni savoir si une correction a vraiment réglé le problème. D’où la règle numéro un du projet.
Le seed : une graine par génération, pas un dé lancé à chaque image
Le seed est un entier calculé une seule fois, au moment de la génération. Il est dérivé du nom de la marque et de l’instant de la génération, passés dans une fonction de hachage de chaîne simple et stable, sans dépendance externe. Ce n’est donc pas un tirage au sens de Math.random : une fois calculé, il est fixé et accompagne le film.
La conséquence est double. D’un côté, deux générations (deux marques, ou la même marque relancée) obtiennent presque toujours des seeds différents, donc des choix de composition différents : le film d’hier ne ressemble pas à celui d’aujourd’hui. De l’autre, avec un seed donné, tout est rejouable. Le hasard est consommé une fois, en amont ; le rendu, lui, ne décide plus rien.
Mulberry32 : un générateur minuscule, rapide, sans surprise
Pour transformer ce seed en suite de nombres, MotionMaker utilise mulberry32, un petit générateur pseudo-aléatoire qui tient en quelques lignes. Il est rapide et reproductible : à seed identique, la suite de nombres est identique. Il suffit pour des choix de mise en scène. Il n’a aucune prétention cryptographique et n’en a pas besoin : on choisit une variante de transition, pas un mot de passe.
Pour que chaque scène tire une suite différente sans marcher sur les autres, le générateur est dérivé du seed combiné à un « sel » : une chaîne qui nomme l’usage (le tempo, une scène, un aspect). Changer l’ordre dans lequel on consulte les tirages ne décale donc rien chez les voisins. Ajouter un nouveau tirage dans une scène ne bouleverse pas les autres.
Un seul endroit où l’on décide
Le choix d’un traitement visuel pour une scène passe par une unique fonction : elle retient l’option explicitement demandée par l’utilisateur s’il y en a une, sinon celle que désigne le seed. Les scènes ne tirent plus elles-mêmes au sort. Un point de décision unique a un avantage très concret : lorsqu’une variante surprend, on sait où chercher, et on peut la forcer pour la comparer à une autre.
Le même principe vaut pour ce que nous appelons la signature de mouvement, c’est-à-dire le caractère de mouvement qui traverse tout le film, durée des transitions comprise. Le rendu et le pipeline lisent la même fonction : la constante de chevauchement n’est jamais dupliquée. Deux copies d’un même nombre finissent toujours par diverger ; une seule source ne le peut pas. Pour le côté artistique de ces chevauchements, voir anticipation et chevauchement en motion design.
La grille rythmique : le montage et le son partent du même tempo
Le déterminisme ne sert pas qu’à reproduire : il sert aussi à synchroniser. Le tempo du montage est tiré du seed dans une fourchette de 96 à 124 battements par minute : en dessous, ça traîne ; au-dessus, les plans deviennent trop courts pour qu’un texte soit lisible dans un format de 15 à 25 secondes. Les coupes tombent sur les temps, ce qui donne au montage cette respiration qu’on voit dans les références professionnelles.
Et cette même grille sert ensuite à fabriquer la bande sonore. Montage et son sont calculés à partir du même tempo, ils ne peuvent donc pas dériver l’un de l’autre : la synchronisation est exacte par construction, jamais réglée à l’oreille.
Deux pièges que l’arrondi plan par plan ne règle pas
En pratique, il a fallu corriger deux défauts mesurés. Le premier : chaque transition consomme un chevauchement, donc la coupe tombe à « durée moins chevauchement », pas à « durée ». Sur un montage réel à 105 battements par minute, les coupes atterrissaient à 72 images là où les temps tombent à 68,6 et 85,7 : hors grille, donc décalées par rapport au son.
Le second : un temps fait rarement un nombre entier d’images (17,14 à 105 battements par minute). Si l’on arrondit plan par plan, l’erreur s’accumule : 1,4 image de dérive à la dernière coupe d’un montage de sept plans, et davantage si le film s’allonge. La correction consiste à calculer les positions de coupe en absolu sur la grille (les temps cumulés depuis le début), puis à en déduire les durées. L’erreur reste alors bornée à une demi-image sur chaque coupe, sans jamais s’additionner.
Rendre déterministe un film écrit par un modèle
Le mode « Carte blanche » pose un problème plus dur : le code du film est écrit par un modèle, et du code libre est plein de sources de non-déterminisme (animations CSS, timers, horloge, aléatoire). Le film doit donc exposer une fonction de rendu pure qui reçoit un numéro d’image et dessine cette image, rien d’autre. Les animations CSS, les rappels d’animation du navigateur, les minuteurs et la date sont gelés ; Math.random est réinitialisé à chaque image.
Et on ne se contente pas de le promettre : le contrôle recalcule une image après les autres pour vérifier qu’elle redonne le même résultat. La comparaison est perceptive (plus de 1 % de pixels nettement différents), parce qu’une comparaison d’empreintes exactes déclenchait de fausses alertes sur le lissage des lettres. Cette leçon est typique : le déterminisme se mesure avec la bonne tolérance, il ne se décrète pas.
Ce que cela change pour vous
- Des corrections ciblées : un défaut peut être reproduit, donc corrigé et vérifié sur la même vidéo.
- Des films différents d’une génération à l’autre : le seed varie, la composition aussi.
- Un son qui tombe sur les coupes, parce que le tempo est commun.
- Des comparaisons honnêtes : deux versions d’un moteur se jugent sur le même seed, pas sur deux tirages chanceux.
Dernier rappel : « vérifier en rendant, pas en relisant ». Plusieurs hypothèses ont été démenties par le rendu lui-même ; le déterminisme est ce qui rend ces comparaisons possibles. Pour la suite, lisez mesurer plutôt que supposer : coût de rendu et mémoire sur iPhone. Pour la vue d’ensemble de l’outil : créer une vidéo depuis un site web.