Washing Line Hero
Le premier écran d’un site web : la barre de la marque et la navigation en haut, un grand titre avec une phrase colorée, une ligne d’introduction, un ou deux boutons et une petite note, et à côté une corde à linge tendue dans le ciel. Sur la corde pend un tissu en coton maintenu par des pinces en bois, imprimé avec le poster de la marque : un nom, une petite ligne, deux grands mots, une colonne de spécifications et un petit graphique à barres. Une brise le soulève de temps en temps et les nuages défilent derrière.
Il est fait pour être touché. Déplacez le curseur sur le tissu et un doigt le creuse. Appuyez et faites glisser, et le tissu suit votre main : tirez un coin vers le haut, pliez-le sur la corde, étirez-le vers vous. Relâchez et il tombe, se balance et se stabilise. Sur les téléphones, un doigt fait la même chose, et la page ne défile pas tant que le tissu est maintenu. Le tissu est simulé (une grille de particules maintenues par des contraintes d’étirement, de cisaillement et de flexion, animée à une fréquence fixe de 120 Hz), il se comporte donc comme un tissu où qu’on le saisisse, plutôt que de jouer une animation préenregistrée.
Vous décrivez le hero et l’impression dans hero.json. La construction vérifie tout et écrit out/index.html, une page entière dans un fichier, et out/embed.html, la même section à coller dans un site existant. Comme la simulation s’exécute à pas fixe depuis un état initial stable, record.mjs peut la parcourir image par image : dans la vidéo, un curseur dessiné tire un coin, le relâche, puis passe un doigt sur le tissu, montrant ce que les visiteurs peuvent faire, identique sur toutes les machines.
Ce qu’il n’est pas : le tissu ne se déchire pas, ne s’emmêle pas et ne s’envole pas de la corde (il n’y a pas d’auto-collision, donc si vous le pliez fort à travers lui-même, il passe à travers et retombe), et l’impression est dessinée par la page à partir de vos mots, pas d’une photo que vous téléchargez.
Ce dont vous avez besoin
- Node.js 18 ou plus récent. Rien à installer.
- Chrome, Chromium ou Edge, pour les vérifications et l’enregistrement (les scripts le trouvent ; définissez
CHROME_PATHs’ils ne le trouvent pas). - ffmpeg, pour la vidéo (
brew install ffmpeg,winget install ffmpeg,apt install ffmpeg; ou définissezFFMPEG_PATH). - Accès Internet lorsque la page est ouverte : three.js et les polices sont chargés depuis jsDelivr à des versions épinglées avec des hachages d’intégrité. Sans cela, les visiteurs voient l’image fixe (la même corde et le même tissu, dessinés à plat) et les polices système ; la page fonctionne quand même.
Le dossier de cette compétence est <skill> ci-dessous : le dossier dans lequel se trouve ce SKILL.md.
Étapes
1. Collecter la marque et les mots
Demandez à la personne, ou trouvez sur son site actuel :
- Nom, et le logo sous forme de fichier SVG (carré ou presque ; simple, sans scripts). Sans cela, jusqu’à trois lettres forment un monogramme.
- Couleurs : l’arrière-plan, qui est aussi le ciel à l’horizon (la couleur du texte doit atteindre un rapport de contraste de 7:1 avec lui), et un accent. Un bleu clair donne un ciel de midi avec du texte sombre ; un bleu nuit profond ou prune donne un ciel crépusculaire avec du texte clair et un soleil bas et chaud.
- Polices : une police d’affichage pour le titre et les grands mots sur le tissu, et une pour le reste. Elles sont chargées épinglées et vérifiées : Space Grotesk, Inter, Instrument Sans, Instrument Serif, DM Sans, Manrope, Fraunces, Sora, Outfit, Bricolage Grotesque, IBM Plex Sans, JetBrains Mono, Plus Jakarta Sans, Newsreader, Playfair Display. Toute autre famille Google Fonts fonctionne aussi, non épinglée.
- Les mots sur la page : un titre de quelques mots avec la phrase à colorer, une ou deux phrases sur ce que c’est et pour qui, le bouton principal et un second facultatif avec leurs destinations, jusqu’à cinq liens de navigation et le bouton dans la barre. Un petit badge au-dessus du titre et une note sous les boutons sont facultatifs.
- Les mots sur le tissu : le nom à imprimer en haut (souvent le produit et la version), une petite ligne en dessous, deux à quatre grands mots (deux lignes sont les plus lisibles), jusqu’à six paires de spécifications courtes (étiquette et valeur), une légende pour le graphique, et une adresse web dans le coin.
Chaque nom, numéro, affirmation et date doit venir de la personne. N’inventez pas de spécifications ou de chiffres ; laissez une spécification de côté si elle n’est pas fournie. Les barres du graphique sont décoratives, générées à partir de la graine, pas des données : donnez-lui une légende qui ne prétend pas afficher des chiffres, ou désactivez-le.
2. Écrire hero.json
Copiez le dossier d’exemple le plus proche et remplacez tout : examples/paperwind/ (une application de notes, ciel de midi clair, quatre pinces) ou examples/halden/ (une marque de lin, ciel crépusculaire, trois pinces, un tissu plus carré).
| Champ | Ce que c’est | Limite |
|---|---|---|
brand.name, brand.href | Le nom en haut à gauche, et où il pointe (par défaut /) | 28 |
brand.logo | Un fichier .svg à côté de hero.json, intégré dans la page ; ou jusqu’à 3 lettres pour un monogramme | – |
nav[] | Jusqu’à 5 { "label", "href" } dans un pill (caché sur téléphone) | 18 |
action | Le bouton en haut à droite, { "label", "href" } ; false pour aucun | 22 |
hero.badge | Une petite ligne en majuscules au-dessus du titre | 40 |
hero.title | Le titre. *phrase* le met dans la couleur d’accent ; \n coupe la ligne (jusqu’à 3 lignes) | 72 |
hero.lede | Ce que c’est et pour qui. Markdown en ligne : code, liens, gras, italique | 220 |
hero.actions[] | 1 ou 2 { "label", "href" } : le premier est le bouton principal plein avec une flèche, le second un contour | 26 |
hero.note | Une petite ligne sous les boutons | 90 |
hero.align | left (corde et tissu à droite, par défaut) ou right (miroir). center met le tissu derrière le texte ; déconseillé | – |
theme.background, theme.ink, theme.accent | Couleurs hexadécimales. ink doit atteindre 7:1 sur background | – |
theme.mode | light ou dark ; calculé à partir de l’arrière-plan s’il est omis | – |
theme.fonts | { "display", "body", "weight" } : noms de familles (false pour la police système) et le poids du titre, 300–800 (par défaut 500) | – |
theme.scrim | 0–1 : à quel point le ciel derrière le texte est estompé vers la couleur d’arrière-plan. Par défaut 0.3 | – |
effect | Le ciel, la corde et le tissu, ci-dessous | – |
motion.speed | 0.25–2, par défaut 1 : la vitesse de tout | – |
motion.pointer | true (par défaut) | – |
meta | title (70) et description (170) pour les résultats de recherche et les aperçus de liens ; url et image (adresses https complètes), lang (par défaut en) | – |
L’impression (effect) : au moins printTitle ou printHeadline.
| Réglage | Limite | Par défaut | Ce que c’est |
|---|---|---|---|
printTitle | 28 caractères | aucun | Le nom en haut de l’impression |
printLine | 64 caractères | aucun | Une petite ligne sous le nom |
printHeadline | 48 caractères | aucun | Les grands mots ; \n coupe la ligne. Ils rétrécissent pour tenir dans leur colonne |
printSpecs | 0 à 6 { "label", "value" }, 12 et 14 caractères | aucun | La colonne des spécifications à droite ; les étiquettes s’impriment en majuscules |
printChart | true / false | true | Un petit graphique à barres sous les spécifications, sa barre la plus haute dans theme.accent |
printChartLabel | 32 caractères | aucun | Légende sous le graphique |
printFoot | 40 caractères | aucun | Petit texte dans le coin inférieur, par exemple une adresse web |
cloth | couleur | #ecebe6 | Le coton |
printInk | couleur | #15181d | L’impression. Doit atteindre 7:1 sur cloth |
La scène (effect), chaque réglage est facultatif :
| Réglage | Plage | Par défaut | Ce qu’il fait |
|---|---|---|---|
seed | 1–9999 | 7 | Génère les nuages et les barres du graphique |
skyTop | couleur | #5f9be0 clair, l’arrière-plan assombri en mode sombre | Le ciel en haut du hero |
skyBottom | couleur | theme.background | Le ciel à l’horizon |
clouds | 0–1 | 0.6 | Quelle partie du ciel est couverte de nuages ; 0 est clair |
cloudColor | couleur | blanc (clair), un violet gris doux (sombre) | Les nuages |
drift | 0–1 | 0.35 | La vitesse à laquelle les nuages dérivent |
light | day, dusk | day pour clair, dusk pour sombre | Soleil de midi venant d’en haut, ou un soleil bas chaud et une lumière de ciel froide |
aspect | 0.8–1.7 | 1.35 | Largeur du tissu par rapport à sa hauteur |
pegs | 2–6 | 4 | Pinces en bois le long du bord supérieur |
peg | couleur | #c39a64 | Les pinces |
rope | couleur | #6f6a62 clair, #cfc6b8 sombre | La corde |
breeze | 0–1 | 0.45 | La force de la brise qui soulève le tissu |
weave | 0–1 | 0.5 | La force à laquelle le tissage uni apparaît de près |
poke | 0–1 | 1 | La profondeur du creux sous le curseur ; 0 le désactive |
drag | true / false | true | Permet aux visiteurs de saisir le tissu et de le tirer |
size | 0.6–1 | 0.76 | Quelle part de l’espace à côté du texte le tissu occupe (il laisse de la place pour être tiré) |
hint | 40 caractères | "Appuyez · Tirez · Relâchez" | Une petite légende dans le coin inférieur éloigné sur les grands écrans pour indiquer aux visiteurs qu’ils peuvent toucher ; " · " sépare ses parties ; vide pour aucun |
Conseils d’écriture : le titre sur la page et les grands mots sur le tissu doivent dire des choses différentes ; le tissu ressemble à un poster, donc gardez ses mots peu nombreux et grands. Deux ou trois paires de spécifications sont plus lisibles que six. Si la marque a un slogan ludique sur la légèreté, le vol, le séchage ou le fait de pendre, le tissu est l’endroit pour le mettre.
3. Construire
node <skill>/scripts/build.mjs hero.json out
Il liste tous les problèmes dans hero.json en une fois (champs manquants, texte dépassant sa limite, réglage hors plage, couleurs sans contraste, encre d’impression trop faible sur le tissu) et n’écrit rien tant qu’ils ne sont pas corrigés. Ensuite, il imprime les réglages utilisés et tout ce qui mérite un coup d’œil, comme un accent assombri pour que le titre soit lisible à 4.5:1.
Il écrit out/index.html (CSS, script, logo et l’image fixe intégrés), out/embed.html et out/assets/logo.svg (l’icône d’onglet).
4. Vérifier
node <skill>/scripts/check.mjs out/index.html
Il charge la page à 390, 768, 1024 et 1440 px et doit dire ok à chaque fois : rien de plus large que l’écran ou coupé, contraste lisible pour chaque ligne de texte par rapport au ciel derrière, nom sur chaque lien et bouton, un seul h1. Les lignes marquées · valent le coup d’œil mais ne font pas échouer.
5. Regarder, et toucher
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 3.5 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 390x844 --scale 2
node <skill>/scripts/screenshot.mjs out/index.html
Le premier est le tissu au repos, le second en milieu de traction (la main scriptée a un coin levé), le troisième le téléphone. Regardez-les : le tissu est-il entièrement à l’écran avec de l’espace autour, l’impression est-elle lisible, les pinces sont-elles sur la corde ? screenshot.mjs exécute Chrome sans GPU, donc il montre l’image fixe que les visiteurs voient sans WebGL ou quand le réseau échoue (dans out/screens/) ; vérifiez qu’elle se lit aussi.
Ensuite, ouvrez out/index.html dans un navigateur et jouez avec : survolez, appuyez, tirez un coin par-dessus la corde, relâchez. Sur un téléphone, faites glisser avec un doigt et vérifiez que la page défile toujours lorsque vous balayez à côté du tissu.
6. Enregistrer la vidéo
node <skill>/scripts/record.mjs out/index.html --seconds 10
Il parcourt le hero pendant 10 secondes à 30 ips en 1920×1080 et écrit out/preview.mp4 et out/poster.png (l’image à 3.5 s, en milieu de traction). Dans la vidéo, un curseur dessiné saisit le coin inférieur à 2.2 s, le tire vers le haut vers vous, le relâche à 4.4 s, et à partir de 6 s, passe un doigt sur le tissu. Options : --size 1080x1350 (portrait), --size 1080x1920, --fps 60, --poster 1.6. Les images sont identiques sur toutes les machines, tant que l’enregistrement commence à 0 (ce qui est toujours le cas).
7. Mettre en ligne
- En tant que page : téléchargez
out/index.htmletout/assets/sur n’importe quel hébergeur statique (Cloudflare Pages, Netlify, Vercel, GitHub Pages, S3). Utilisezout/poster.png(ou un recadrage 1200×630 de celle-ci) commemeta.image, téléchargé avec le site. - Dans un site existant : collez
out/embed.htmlà l’endroit où se trouve le hero. Tout est sous la portée de#mh-washing-line; déplacez les<link>de polices dans le<head>si vous le souhaitez. Si le site a déjà un<script type="importmap">, fusionnez les entréesimportsetintegrityde l’embed dedans. La section fait toute la hauteur de la fenêtre ; définissez--mh-heightdessus (par exemplestyle="--mh-height:760px") pour la réduire. Dans React ou d’autres frameworks, mettez le balisage dans le composant et les balises<script>dans la page, ou rendez-le dans un iframe. - Pour changer l’impression, modifiez
hero.jsonet reconstruisez.
Dépannage
build: fix hero.json first: chaque ligne nomme le champ et ce qu’il faut changer ; les problèmes de couleur suggèrent une couleur qui fonctionne.- Le tissu est coupé au bord : réduisez
size, ou rendez le tissu plus carré (aspectproche de 1). - Les grands mots sur le tissu sont petits : ils rétrécissent pour tenir à côté de la colonne des spécifications. Utilisez moins de mots, un
\n, ou moins de spécifications et pas de graphique (les mots prennent alors toute la largeur). - Le tissu ne se stabilise pas, ou bat trop : réduisez
breeze. - Le creux est trop fort ou trop faible :
poke(0 le désactive ; le déplacement fonctionne toujours). record: the effect didn't start: la page est retombée sur son image fixe : Chrome n’a pas pu charger three.js depuis jsDelivr (vérifiez la connexion ou un proxy) ou n’a pas de WebGL.ffmpeg not found: installez-le ou définissezFFMPEG_PATH.- Les visiteurs voient un tissu immobile : leur navigateur a WebGL désactivé ou le CDN est bloqué (l’image plate), ou ils ont demandé un mouvement réduit (une image du tissu vivant au repos, qui ne bouge pas). C’est intentionnel.
- Sur un téléphone, la page ne défile pas : elle arrête seulement le défilement tant qu’un doigt tient le tissu ; balayez à côté. Si le tissu remplit l’écran du téléphone, réduisez
size.
Fichiers
scripts/build.mjs,scripts/record.mjs: ce que vous exécutez. Ils appellent le kit Motion Heroes.scripts/kit/: le kit partagé par chaque compétence Motion Heroes : la construction et les vérifications (build.mjs), le CSS de la section (shell.css), le runtime du navigateur (runtime.js: horloge, pause, rapport de pixels, mouvement réduit, repli), l’enregistreur (record.mjs,cdp.mjs), les three.js et polices épinglées (three.json,fonts.json) etKIT.md, qui les explique.scripts/effect/: la corde à linge elle-même :effect.mjs(ses réglages, les vérifications et l’image fixe),effect.js(le shader du ciel, …