Contrat d'architecture front-end Pryne
Les décisions structurelles essentielles des builds vanilla-JS de Pryne, leur raison d'être, et les invariants que vous ne devez pas briser. Implémentation de référence : design-demos/ dans le dépôt Portfolio (test) (~/Documents/Coding Folder/Portfolio (test)), build actif v4-d-hybrid.html + js/roll-*.js, en date du 22/07/2026.
Jargon, défini une fois : IIFE = Immediately Invoked Function Expression, (function () { ... })(); — une fermeture au niveau du fichier, donc rien ne fuit sauf ce que le fichier expose explicitement sur l'espace de noms partagé. Amélioration progressive = la page est entièrement utilisable sans aucune amélioration JS ; les couches de comportement plus riches ne s'activent que lorsque leur dépendance est effectivement chargée. Develop-plate = l'œuvre graphique sur toile de ce projet qui se « développe » (se résout à partir du bruit) lorsque l'utilisateur interagit.
Quand NE PAS utiliser cette compétence
- Théorie du timing, de l'assouplissement, de la chorégraphie des animations → pryne-motion-reference
- Savoir si une modification est même autorisée, et comment elle est contrôlée → pryne-change-control
- Quelque chose est cassé et vous diagnostiquez → pryne-frontend-debugging
- Prouver qu'une modification fonctionne (captures d'écran, Lighthouse, grille d'évaluation) → pryne-validation-and-qa
- Projets React/Next.js ou tout projet avec un bundler — ce contrat est uniquement pour les sites vanilla sans build.
Le contrat des modules
Une préoccupation par fichier. Une IIFE par fichier. Pas de bundler, pas d'imports.
Tout l'état inter-modules vit sur un seul objet d'espace de noms global — ici window.Roll. roll-core.js le crée et se charge en premier ; chaque autre module commence par const Roll = window.Roll; et lit/écrit des propriétés sur celui-ci (roll-core.js:1-7 le stipule explicitement). Les modules qui ne doivent pas se connaître communiquent via des événements DOM à la place (par exemple, roll-scroll.js émet roll:launch ; roll-contact-sheet.js écoute — voir roll-scroll.js:35-37).
L'ordre des scripts dans le HTML est le graphe de dépendances. Extrait de v4-d-hybrid.html:429-437 :
roll-core.js → roll-shader.js → roll-field.js → roll-audio.js → roll-cursor.js
→ vendor/lenis.min.js → roll-scroll.js → roll-contact-sheet.js → roll-eggs.js
Invariant : ne jamais réordonner ni insérer de <script> sans d'abord chercher ce que le module lit depuis Roll et confirmer que chaque producteur se charge plus tôt. Il n'y a pas de système d'imports pour vous sauver ; un réordonnancement échoue silencieusement ou lève une erreur au chargement.
grep -n "Roll\.\w*" design-demos/js/<module>.js # ce qu'il lit/écrit
GSAP est délibérément ABSENT de cette chaîne — voir l'invariant 2.
Carte des modules (en date du 22/07/2026)
| Fichier | Une préoccupation | Lignes |
|---|---|---|
roll-core.js | Espace de noms, état partagé, moteur develop-plate, upgradeMotion | 192 |
roll-scroll.js | L'épine dorsale : entrée, chorégraphie du défilement, HUD, boucle rAF principale, Lenis | 226 |
roll-field.js | Champ de toile d'arrière-plan | 136 |
roll-shader.js | Shader WebGL grain/lumière + fallback Canvas 2D | 133 |
roll-eggs.js | Déclencheurs de personnalité cachés (niveau whisper uniquement) | 83 |
roll-audio.js | Son ambiant silencieux lié à la vélocité de défilement | 79 |
roll-contact-sheet.js | Révélation de la planche-contact au lancement | 55 |
roll-cursor.js | Curseur personnalisé (bureau uniquement, contrôlé par GSAP) | 36 |
Nouvelle fonctionnalité interactive ? C'est un nouveau fichier roll-*.js (ou une section clairement délimitée du module propriétaire de cette préoccupation), ajouté à la chaîne de scripts en position de dépendance — pas de <script> en ligne dans le HTML.
Invariants (vérifiés dans le code — maintenez-les vrais)
- Le 'reduced motion' contrôle chaque module d'animation.
Roll.reduced = matchMedia('(prefers-reduced-motion: reduce)').matches(roll-core.js:9). Chaque module le consulte : le shader saute le WebGL (roll-shader.js:90,124), le champ saute sa boucle rAF (roll-field.js:125,135), la planche-contact retourne tôt (roll-contact-sheet.js:12), le défilement saute l'entrée hold-to-develop et Lenis (roll-scroll.js:39-40,152), et le CSS annule les transitions clip-path (v4-d-hybrid.html:293-295). Toute nouvelle animation doit vérifierRoll.reduced(JS) ou se trouver sous la media query reduced-motion (CSS). - GSAP est une amélioration progressive, jamais une dépendance. Il se charge en
asyncdepuis un CDN avec un hash SRI (v4-d-hybrid.html:440) ; au chargement, il appelleRoll.upgradeMotion(), qui basculeRoll.enhancedet vide les callbacks enregistrés viaRoll.onMotionReady(roll-core.js:10-15,186-191). Si GSAP n'arrive jamais, le site doit rester entièrement fonctionnel — le curseur, le type hero et le skew restent simplement au niveau de base (roll-cursor.js:34-35,roll-scroll.js:32-33,89,196). Enregistrez le code dépendant de GSAP avecRoll.onMotionReady(fn); n'appelez jamaisgsap.*de manière inconditionnelle. - Les prises de contrôle visuelles risquées sont protégées par des blocs défensifs — sur le chemin récurrent, pas seulement lors de la configuration. Le curseur personnalisé est protégé à trois niveaux, chacun avec un catch de restauration qui met à null
Roll.cursorUpdateet supprime.custom-cursor(qui cache le curseur OS) : la configuration (roll-cursor.js:9-32, catch à 32), le corps du gestionnaire par événement (roll-cursor.js:17-20), et le site d'appel depointermove(roll-core.js:26-29). Un échec à n'importe quel point — lors de la configuration ou lors d'un mousemove ultérieur — restaure le curseur OS (corrigé le 22/07/2026 ; contrat de sécurité dans l'en-tête du fichier,roll-cursor.js:1-5). Lors de l'application de ce modèle à tout ce qui cache/remplace une affordance native, protégez également le chemin récurrent, pas seulement la configuration. - Les révélations par clip-path vivent sur un wrapper intérieur, jamais sur l'élément observé par IntersectionObserver (le « correctif concept-C » — nommé d'après le concept v4 C,
v4-c-ch001.html, d'où il est originaire avant d'être intégré à v4-d). Le IO observe.panel; le clip-path anime.panel-inner(v4-d-hybrid.html:121-122,185-186). Raison : découper l'élément observé modifie sa géométrie d'intersection et la révélation entre en conflit avec le déclencheur. - Les visuels basés sur l'engagement sont conditionnés par leur propre visibilité, pas par le chargement de la page. Les plaques de fonctionnalités ne se développent que lorsque leur panneau a la classe
.in(roll-scroll.js:204-219) ; le commentaire du code enregistre le bug original : les plaques finissaient de se résoudre avant que quiconque ne les ait atteintes en défilant, « tuant silencieusement l'interaction 'se développe au fur et à mesure que vous interagissez' ». Le commentaire d'en-tête dev4-d-hybrid.htmlqualifie ce correctif de priorité absolue issue de l'audit technique. - Le WebGL est explicite et avec un fallback sûr. Alpha non prémultiplié à la création du contexte (
roll-shader.js:17),gl.clearexplicite à chaque frame (roll-shader.js:95), le contexte 2D n'est acquis qu'après que WebGL a eu sa chance — une toile ne peut avoir qu'un seul type de contexte (roll-shader.js:9-12), etwebglcontextlostéchoue silencieusement au lieu de faire planter la boucle de rendu (roll-shader.js:129-132). Les appelants utilisent le point d'entrée uniqueRoll.shader.render(t)et ne savent jamais s'il s'agit de GL ou de 2D. - Le défilement reste natif sous Lenis. Lenis est vendorisé (
js/vendor/lenis.min.js, pas CDN), instancié uniquement quand!Roll.reduced, et maintientwindow.scrollYvalide — c'est une amélioration de sensation, pas un détournement du défilement (roll-scroll.js:148-152,167). La boucle de rendu litscrollYcomme avant.
Philosophie des démos mono-fichier + tokens de design
Chaque variante de design est un fichier HTML autonome (CSS en ligne, modules js/ partagés) afin que les variantes puissent être comparées, capturées et testées A/B comme des artefacts complets — voir pryne-design-direction-decision. Un long commentaire d'en-tête dans chaque fichier enregistre ce qu'est la variante et quelles conclusions d'audit elle porte (lisez-le avant de modifier ; c'est le journal de bord local du fichier).
Toutes les couleurs, espacements et assouplissements sont des propriétés personnalisées CSS dans :root (v4-d-hybrid.html:50-63) :
:root {
--bg: #0a0a0b; --accent: #d2232e; --ink: #f4f3f1; --dim: #86868c;
--pad-x: clamp(1.25rem, 6vw, 6rem);
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
--ease-snap: cubic-bezier(0.16, 1, 0.3, 1);
}
Selon les règles globales de Pryne : ne jamais coder en dur une couleur/taille là où un token existe ; les valeurs fluides utilisent clamp(). Toute nouvelle animation doit réutiliser --ease-out/--ease-snap sauf si pryne-motion-reference dit le contraire — un langage d'assouplissement par build.
Liste de contrôle : ajout d'un module
- Nouveau
roll-*.js(ou module propriétaire existant correct), IIFE de premier niveau,const Roll = window.Roll; -
<script>inséré après tout ce qu'il lit depuisRoll, avant tout ce qui le lit - Vérifie
Roll.reduced; utilisation de GSAP uniquement dansRoll.onMotionReady - Tout ce qui cache une affordance native est enveloppé dans un try/catch avec un catch de restauration
- Conditionné par la visibilité si basé sur l'engagement ; cible IO ≠ cible clip-path
- Tokens, pas de valeurs codées en dur
- Ensuite, valider selon pryne-validation-and-qa
Points faibles connus (ouverts, énoncés clairement)
- Pas d'étape de build : pas de minification, pas de bundling ; acceptable pour les démos, non résolu pour le déploiement en production.
- Les polices sont chargées depuis le CDN Google Fonts (
v4-d-hybrid.html:47-48) malgré l'intention initiale du projet de les auto-héberger (l'auto-hébergement est mentionné dansdesign-demos/DECISIONS.mdseulement en passant, dans l'entrée Lenis ; l'enregistrement de décision lui-même est antérieur au fichier ; pas encore fait). GSAP est également toujours sur CDN (épinglé + SRI). Voir pryne-change-control avant de « corriger » l'un ou l'autre. - Pas de tests automatisés — la validation repose uniquement sur des preuves basées sur le navigateur (pryne-validation-and-qa).
- Contenu fictif : les études de cas/la biographie ne sont pas définitives ; ne peaufinez pas le texte comme s'il l'était.
Provenance et maintenance
Exécutez scripts/verify.sh (dans le répertoire de cette compétence) pour vérifier tous les points ci-dessous en une fois.
Basé sur le dépôt Portfolio (test) au commit 457868a, le 22/07/2026. Revérifiez avant de vous fier à des faits volatils :
- Ordre des scripts :
grep -n "<script" design-demos/v4-d-hybrid.html - Nombre de lignes / liste de modules :
wc -l design-demos/js/*.js - Couverture reduced-motion :
grep -rn "Roll.reduced\|prefers-reduced-motion" design-demos/ - GSAP toujours CDN+SRI, polices toujours CDN :
grep -n "cdn.jsdelivr\|fonts.googleapis" design-demos/v4-d-hybrid.html - Lenis toujours vendorisé :
ls design-demos/js/vendor/ - Le build actif est toujours v4-d : vérifiez
design-demos/DECISIONS.mdet le derniergit log --oneline