Comment concevoir un Désastre ?
Vue d’ensemble
Les désastres sont un système d’effets visuels et sonores qui se déclenchent automatiquement sur le site selon des règles définies. Ils créent des expériences interactives surprenantes et ludiques pour les visiteurs.
Le système repose sur trois composants principaux :
-
Règles : Conditions de déclenchement basées sur le contenu (titre, artiste, etc.)
-
Recettes : Configuration des effets à appliquer
-
Désastres : Implémentations JavaScript/CSS des effets visuels
Architecture
Structure des fichiers
src/
├── apps/frontend/config/desastres/
│ ├── desastres.yml # Configuration principale avec imports
│ ├── regles/ # Règles de déclenchement
│ │ ├── colors.yml
│ │ ├── misc.yml
│ │ └── ...
│ ├── recettes/ # Configuration des effets
│ │ ├── mangelettres.yml
│ │ ├── tts.yml
│ │ ├── splitouine.yml
│ │ └── ...
│ └── schemas/ # Schémas de validation JSON
│ ├── regles.schema.json
│ ├── recettes.schema.json
│ └── desastres-main.schema.json
└── web/desastres/ # Implémentations des désastres
├── mangelettres/
├── splitouine/
├── fish/
├── light/
├── tts/
└── ...
Types de désastres
Désastres visuels
mangelettres
Fait disparaître progressivement certaines lettres du texte.
Technologie : GSAP SplitText
Options :
-
rate: Taux de suppression (0.0 à 1.0) -
letters: Lettres à supprimer (ex: "aeiou") -
selector: Sélecteur CSS de l’élément cible
Exemple :
recettes:
mange_voyelles:
enabled: true
desastre: mangelettres
options:
rate: 0.5
letters: "aeiou"
selector: "section.content"
splitouine
Animation de texte avec effets de division et de mouvement.
Technologie : GSAP SplitText
Caractéristiques :
-
Division du texte en caractères individuels
-
Animations fluides et personnalisables
-
Effets de rotation, translation, opacité
fish (démo)
Affiche un poisson animé qui suit le curseur de la souris.
Technologie : Lottie
Comportement :
-
Suivi du curseur avec décalage vertical
-
Animation Lottie en boucle
-
Superposition en z-index élevé
light (démo)
Crée des rayons lumineux traversant la page.
Technologie : CSS + Web Animations API
Effet :
-
Trois rayons lumineux animés
-
Déplacement horizontal de gauche à droite
-
Rotation à 45°
musique (démo)
Retire les lettres "M" et les fait défiler sur une portée musicale SVG.
Technologie : anime.js + SVG
Particularités :
-
Extraction des lettres "M" et "m"
-
Génération dynamique d’une portée SVG
-
Animation sinusoïdale des lettres
Désastres sonores
tts (Text-to-Speech) (démo)
Synthèse vocale du contenu de la page.
Technologie : Web Speech API
Options configurables :
-
rate: Vitesse de lecture (0.1 à 10, ou plage [min, max]) -
pitch: Hauteur de la voix (0 à 2, ou plage [min, max]) -
volume: Volume (0 à 1, ou plage [min, max]) -
lang: Code langue (ex: "fr-FR", "en-US") -
voices: Liste de noms de voix préférées -
texts: Textes à lire (si non fourni, lit le contenu de la page)
Exemple :
recettes:
tts_robot:
enabled: true
desastre: tts
options:
rate: [0.8, 1.2] # Vitesse aléatoire entre 0.8 et 1.2
pitch: [0.5, 0.7] # Voix grave
volume: 0.8
lang: "fr-FR"
voices: ["Google français", "Microsoft Hortense"]
Désastres sur le son
bande-usee
Le premier désastre qui touche le morceau et non la page. Le site s’appelle Musique Approximative ; celui-ci prend ce nom au mot et fait flotter la hauteur du son, comme une bande magnétique passée trop de fois.
Une ligne à retard modulée dans un AudioWorklet — un retard qui varie est une hauteur qui
varie. Deux oscillations superposées : le wow lent, le flutter rapide.
Trois couches, une seule modulation. L’oreille l’entend, l’œil la voit dériver sur le titre, la main la sent dans la réponse de la page au pointeur. Les contrepoints partagent le signal du processeur, ils ne l’imitent pas : c’est ce qui fait comprendre que l’effet est voulu. Un son qui flotte seul se lit comme une panne, et un visiteur qui croit le site cassé s’en va.
Le curseur n’est pas ralenti — aucune API ne le permet — c’est la page qui met du temps à le remarquer. Aucune propriété de mise en page n’est transitionnée : les clics restent exacts.
Deux sorties. prefers-reduced-motion: reduce retire les deux contrepoints en laissant le
son ; ?sans-desastre retire tout. La seconde existe parce qu’aucun réglage standard ne
permet de refuser une altération sonore — sans elle, ce serait le seul désastre auquel on ne
peut pas échapper.
L’usure suit l’âge du morceau. Le catalogue va de juin 2008 à aujourd’hui — 6 643 jours, 8 216 morceaux — et l’ancienneté n’avait jamais rien déclenché ni modulé. Elle module désormais l’intensité :
| morceau de | intensité | amplitude |
|---|---|---|
2026 |
0,15 |
4,4 cents |
2016 |
0,45 |
13,1 cents |
2011 |
0,74 |
21,6 cents |
2008 |
1,00 |
28,6 cents |
La courbe — plancher 0,15 puis exposant 2 — a été choisie sur les morceaux réels. Une
courbe linéaire placerait 43 % du catalogue dans la bande la plus altérée, ce qui ferait de
l’usure l’état normal plutôt que la marque d’un âge. Le plancher existe parce que sans lui,
29 % des morceaux recevraient une altération inaudible alors que l’en-tête X-Desastre
annonce le désastre.
La référence de dix-huit ans est une constante, et non l’étendue du catalogue : celle-ci grandit chaque jour, et l’usure d’un morceau donné dériverait sans que personne ne l’ait décidé.
La date de publication est lue dans la page, où elle ne figurait jusqu’alors nulle part — notable pour une archive de dix-huit ans. Elle n’est pas réservée au désastre.
Détail d’arborescence qui a sa raison : le processeur vit sous worklet/ et non
javascript/, que le gestionnaire charge automatiquement en script classique — où
AudioWorkletProcessor n’existe pas.
Voir src/web/desastres/bande-usee/README.adoc.
Configuration
Définir une règle
Les règles déterminent quand un désastre se déclenche.
Structure :
# yaml-language-server: $schema=../schemas/regles.schema.json
regles:
- query: "query.title ~ /.*bleu.*/i"
recettes: [bleu]
probability: 0.7
trigger: debug_bleu
Propriétés :
-
query(requis) : Expression de condition-
Syntaxe :
query.FIELD ~ /REGEX/FLAGS -
Champs disponibles :
title,artist,album, etc.
-
-
recettes(requis) : Liste des recettes à appliquer -
probability: Probabilité de déclenchement (0.0 à 1.0, défaut: 1.0) -
trigger: Paramètre URL pour forcer le déclenchement (ex:?debug_bleu)
Unicité :
Une règle n’est évaluée qu’une fois, même si elle est déclarée dans plusieurs des fichiers
importés par desastres.yml. Deux déclarations sont la même règle lorsque leur query,
leur probability, leurs recettes et leur trigger sont identiques — c’est la copie
d’un bloc d’un fichier à l’autre. Sans ce dédoublonnage, une règle à probability: 0.7
déclarée deux fois se déclencherait dans 91 % des cas au lieu de 70 %.
Deux règles qui ne diffèrent que par leur trigger restent en revanche deux règles :
les fusionner reviendrait à supprimer un déclencheur, et un désastre ne doit jamais être
observable seulement par tirage.
Une recette désignée par plusieurs règles satisfaites n’est appliquée qu’une fois, au rang de la première règle qui la désigne. C’est le cas courant lorsque deux conditions se recouvrent.
Exemples de conditions :
# Titre contient "fish" ou "poisson"
query: "query.title ~ /.*(fish|poisson).*/i"
# Artiste exact
query: "query.artist == 'Kraftwerk'"
# Titre commence par "La"
query: "query.title ~ /^La .*/i"
Créer une recette
Les recettes définissent comment le désastre se comporte.
Structure :
# yaml-language-server: $schema=../schemas/recettes.schema.json
recettes:
nom_recette:
enabled: true
desastre: type_desastre
scripts:
- "/desastres/shared/gsap.min.js"
- "/desastres/mangelettres/javascript/mangelettres.js"
options:
# Options spécifiques au désastre
rate: 0.5
selector: "section.content"
Propriétés :
-
enabled(requis) : Active/désactive la recette -
desastre(requis) : Type de désastre (correspond au dossier dans/desastres/) -
scripts: Scripts JavaScript à charger -
options: Configuration spécifique au désastre
Validation avec JSON Schema
Le système utilise des schémas JSON pour valider la configuration.
Avantages :
-
✅ Autocomplétion dans VSCode, IntelliJ
-
✅ Validation en temps réel
-
✅ Documentation intégrée
-
✅ Prévention d’erreurs
Installation dans VSCode :
-
Installer l’extension YAML (Red Hat)
-
Ajouter la directive
# yaml-language-serveren haut des fichiers -
Profiter de l’autocomplétion ! 🎉
Validation en ligne de commande :
npm install -g ajv-cli
# Valider un fichier de règles
ajv validate -s schemas/regles.schema.json -d regles/colors.yml
# Valider un fichier de recettes
ajv validate -s schemas/recettes.schema.json -d recettes/tts.yml
Développement
Créer un nouveau désastre
-
Créer le dossier dans
src/web/desastres/mon-desastre/mkdir -p src/web/desastres/mon-desastre/javascript mkdir -p src/web/desastres/mon-desastre/css -
Créer le fichier JavaScript
javascript/mon-desastre.js/** * Désastre Mon Désastre */ (function() { console.log('🎭 Désastre "mon-desastre" activé'); // Récupérer les options depuis window.desastreOptions const options = window.desastreOptions || {}; // Implémenter l'effet function appliquerDesastre() { // Votre code ici } // Initialiser if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', appliquerDesastre); } else { appliquerDesastre(); } })(); -
Créer le fichier CSS (optionnel)
css/mon-desastre.css -
Créer la recette dans
src/apps/frontend/config/desastres/recettes/mon-desastre.yml# yaml-language-server: $schema=../schemas/recettes.schema.json recettes: mon_desastre: enabled: true desastre: mon-desastre scripts: - "/desastres/mon-desastre/javascript/mon-desastre.js" options: # Vos options personnalisées intensity: 0.8 -
Créer la règle dans
src/apps/frontend/config/desastres/regles/mon-desastre.yml# yaml-language-server: $schema=../schemas/regles.schema.json regles: - query: "query.title ~ /.*test.*/i" recettes: [mon_desastre] probability: 1.0 trigger: debug_mon_desastre -
Importer dans la configuration principale
desastres.ymlimports: - { resource: regles/mon-desastre.yml } - { resource: recettes/mon-desastre.yml } -
Documenter : Créer
src/web/desastres/mon-desastre/README.adoc
Bibliothèques disponibles
Le système utilise plusieurs bibliothèques JavaScript :
-
GSAP : Animations avancées
-
Core :
gsap.min.js -
SplitText :
SplitText.min.js
-
-
anime.js : Animations légères
-
Lottie : Animations vectorielles
-
Web Speech API : Synthèse vocale (natif)
Chemin des bibliothèques partagées :
/desastres/shared/
├── gsap.min.js
├── SplitText.min.js
└── ...
Liste des désastres disponibles
| Nom | Description | Technologie |
|---|---|---|
|
Effet visuel d’amour |
CSS/JS |
|
Fond bleu |
CSS |
|
Animation de danse |
JS |
|
Poisson qui suit le curseur |
Lottie |
|
Effet Kraftwerk |
JS |
|
Rayons lumineux |
Web Animations API |
|
Images aléatoires |
JS |
|
Suppression de lettres |
GSAP SplitText |
|
Portée musicale avec lettres M |
anime.js + SVG |
|
Fond noir |
CSS |
|
Effet de postillons |
JS |
|
Redirection URL |
JS |
|
Effet robotique |
JS |
|
Effet sale/glitch |
JS |
|
Animation de texte |
GSAP SplitText |
|
Synthèse vocale |
Web Speech API |
Ce que coûte un désastre, et pourquoi il n’y a pas de générateur
Le coût, mesuré
Un désastre complet demande aujourd’hui cinq fichiers dans quatre répertoires :
|
la recette — ce que le désastre fait |
|
la règle — quand il se déclenche |
|
deux lignes d’import à déclarer, une par fichier |
|
le comportement |
|
l’apparence |
Plus deux schémas JSON à respecter, validables avec ajv — voir « Validation avec JSON
Schema » ci-dessus.
La fréquence, mesurée
Les dix-neuf recettes existantes sont apparues sur deux jours, les 9 et 10 novembre
2025. Pas par un import massif : par pull requests distinctes et nommées — SPOOOOOKYYYYY
(#18), Desastres-plomberie (#20), Consonnards et Voyellistes (#23), Plomberie (#27).
Elles ont bien été écrites une à une, en rafale.
Depuis : 27 commits sur les désastres en novembre 2025, 3 en janvier 2026, 4 en août 2026. Aucun désastre neuf en neuf mois.
La décision
Il n’y a pas de générateur, et il n’y en aura pas tant que la mesure ressemblera à celle-ci. Outiller une tâche qui n’a pas été faite une seule fois depuis neuf mois coûterait plus qu’elle ne rendrait — l’outil serait à écrire, à comprendre, à maintenir, et à corriger à chaque évolution du format.
|
À quelle condition cette décision se révise. Si une rafale d’écriture reprend — disons trois désastres neufs en un mois — la question mérite d’être reposée, avec la mesure refaite. Le raisonnement ci-dessus ne vaut que par ses chiffres, et ils sont datés du 2026-08-19. Ce qui ne serait pas une raison de la réviser : trouver l’écriture fastidieuse une fois. Le coût est de cinq fichiers ; ce qui coûtait réellement était de ne pas savoir où ils vont, et c’est cette page qui y répond désormais. |
Bonnes pratiques
Performance
-
Lazy loading : Les scripts ne sont chargés que si le désastre est déclenché
-
Probabilités : Utilisez
probabilitypour éviter la lassitude -
Cleanup : Nettoyez les événements et éléments DOM créés
Accessibilité
-
Respect du prefers-reduced-motion :
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (prefersReducedMotion) { // Désactiver ou réduire les animations return; } -
Contrôles : Permettre de désactiver les effets
-
Audio : Respecter les préférences de volume
Troubleshooting
Le désastre ne se déclenche pas
-
Vérifier la règle : La condition est-elle remplie ?
console.log('Titre:', document.title); -
Vérifier la probabilité : Essayer avec
probability: 1.0 -
Utiliser le trigger : Forcer avec
?debug_nom_desastre -
Vérifier les scripts : Ouvrir la console pour voir les erreurs
Erreur de chargement de script
-
Vérifier le chemin dans
scripts -
S’assurer que le fichier existe
-
Vérifier les permissions