Communitygithub.com

TLucas97/tarcsweb

Style maison pour les visuels explicatifs dessinés avec mcp__visual__render_ui (diagrammes, flux, petits graphiques, explications animées). À lire une fois par session avant le premier appel render_ui explicatif. Pas pour les prototypes de composants ; ceux-ci suivent le design donné par l'utilisateur.

Qu'est-ce que tarcsweb ?

TLucas97/tarcsweb est un skill d'agent IA destiné à produire des visuels explicatifs cohérents et lisibles via l'outil `mcp__visual__render_ui`. Il définit un style graphique maison — encre sombre, un seul accent vert, fond blanc, typographie soignée — pour garantir que l'image statique finale (le `frame final`) soit compréhensible sans l'animotion, celle-ci servant uniquement à montrer l'ordre des éléments. Le skill insiste sur la lisibilité en fixant une taille de texte minimale de 16px, une grille d'espacement de 8px, et des règles de mise en page (lecture de gauche à droite, pas plus de deux rangées, largeur ajustée au contenu). Il couvre également l'animotion avec GSAP ou l'API `animate` native, en privilégiant des transitions douces (opacité, translation, échelle) et une durée totale typique de 2 à 4 secondes. Pour les graphiques complexes, les formules mathématiques ou le code, il oriente vers des bibliothèques spécialisées (d3, KaTeX, highlight.js, elkjs) plutôt que de les reproduire à la main. Le skill est conçu pour les explications techniques où la clarté prime sur l'ornementation : pas de dégradés, d'ombres portées ou d'émojis.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/TLucas97/tarcsweb/tree/HEAD/mods/visual/skills/visual-explainer

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Expliqueur visuel

L'image que l'utilisateur voit est la dernière image. Le bouton de lecture rejoue le mouvement une fois. Donc l'image fixe doit s'expliquer d'elle-même ; le mouvement montre seulement l'ordre des choses.

Voici le style maison : encre sombre, un accent vert et un timing calme, sur fond blanc avec des traits fins au lieu d'ombres.

Lisibilité d'abord

L'image est dessinée à côté du texte du terminal en 15px environ. Tout ce qui est plus petit se lit moins bien que le chat autour, donc l'utilisateur ne peut pas le lire.

  • Pas de texte en dessous de 16px (code 15px). Si ça ne tient pas, réduisez le contenu ou divisez-le en deux visuels ; ne réduisez jamais la police.
  • Police : Atkinson Hyperlegible (conçue pour la lisibilité), avec les polices de secours ci-dessous. Corps 400, titres 700.
  • Moins de choses par image : environ 5 nœuds par rangée, deux rangées au maximum.

Tokens

:root{
  --bg:#fff;          /* toujours blanc */
  --ink:#1d2520;      /* texte principal, traits principaux */
  --muted:#5f6561;    /* texte secondaire, étiquettes sur les lignes */
  --faint:#9aa19c;    /* nœuds inactifs, chemins de retour/optionnels */
  --line:#e4e4e0;     /* bordures de cartes, séparateurs, grille */
  --tint:#f4f2ef;     /* remplissage rare : puces de code, ligne surlignée */
  --accent:#3b7a57;   /* la SEULE couleur : le chemin qui compte */
  --bad:#9a4b3c;      /* seulement pour une marque "non / bloqué", jamais décoratif */
}
body{font:400 18px/1.4 "Atkinson Hyperlegible",Inter,system-ui,sans-serif;color:var(--ink)}
code{font:15px "Intel One Mono",ui-monospace,monospace}
  • Échelle de police : titre 26px/700, étiquette de nœud 18px, sous-étiquette et étiquettes de ligne 16px. Titre letter-spacing:-.01em. Les nombres reçoivent font-variant-numeric:tabular-nums.
  • Traits : bordures 1px. Connecteurs 1.5px, stroke-linecap:round. Rien de plus épais que 2px.
  • Rayons : cartes 10px, puces 8px, pilule de token 999px. Pas d'autres valeurs.
  • Espacement : grille de 8px. Remplissage du corps 24px. Remplissage de carte 14px 18px. Écart entre les nœuds 96-120px, pour qu'une étiquette de ligne tienne.
  • Utilisation de l'accent : un chemin, une bordure, ou une puce. Si deux choses sont vertes, l'une d'elles ne devrait pas l'être.

Canvas

  • Largeur = contenu + remplissage de 48px. Typiquement 600-1100. Jamais en pleine largeur "pour remplir". Le contenu commence en haut à gauche.
  • Lignes : hauteur du contenu + 48px, divisé par 19, arrondi au supérieur. Un flux d'une ligne fait 9-11 lignes ; deux niveaux 16-20. Maximum 30.
  • Large et court bat long et étroit. Préférez un flux de gauche à droite ; passez à une deuxième rangée avant de devenir trop haut.
  • Le style de base est blanc, remplissage 16px, box-sizing:border-box, overflow:hidden. Définissez body{padding:24px} et le fond vous-même de toute façon.

Mise en page

  • Ordre de lecture : titre en haut à gauche, puis de gauche à droite, puis de haut en bas. L'animation suit le même ordre.
  • Le titre est une phrase simple énonçant le message à retenir ("Un cache hit contourne la base de données"), pas un sujet ("Mise en cache").
  • Les cartes seulement pour les choses qui existent (un service, une table, un compte, une étape). Les étiquettes, valeurs et notes sont du texte nu.
  • Connecteurs : superposition SVG (position:absolute;inset:0;overflow:visible) dans le même parent positionné que les nœuds. Mesurez les extrémités avec getBoundingClientRect() ; ne codez jamais en dur les coordonnées. Laissez un écart de 8px entre la ligne et la carte.
  • Pointes de flèche : un chemin chevron ouvert l5 4-5 4 dans la couleur de la ligne. Pas de triangles remplis, pas de valeurs par défaut <marker>.
  • Lignes droites d'abord. Courbes seulement pour contourner quelque chose : une cubique, tangentes horizontales (C midX y1, midX y2, x2 y2).
  • Un chemin qui ne se produit pas : couleur --faint, pointillé 2 5. Un chemin bloqué : pareil, plus un petit x --bad en son milieu.
  • Les étiquettes de ligne sont centrées au-dessus de la ligne en --muted 16px, 2-3 mots.
  • Données en mouvement (une requête, un montant, un message) sont une petite pilule sombre : fond --ink, texte blanc 16px, rayon 999px. Elle se termine garée là où elle est arrivée, pour que l'image fixe la montre.
  • Graphiques : un axe, ligne de 2px ou barres fines, lignes de grille en --line, la série qui compte en --accent et les autres en --faint, étiquettes directes au lieu d'une légende, valeurs en encre (jamais dans la couleur de la série). Si un nombre est le point important, montrez le nombre, pas un graphique.

Mouvement

  • Chaque scène se termine par une image finale significative. Pas de sorties, pas de boucles, pas de fondus sortants. L'animation totale se termine au moins 200ms avant duration_ms.
  • Durée totale typique 2-4s. Restez sous 6s sauf s'il s'agit d'une histoire en plusieurs étapes. duration_ms = dernière fin + 300ms.
  • Ordre : titre, puis nœuds dans l'ordre de lecture, puis les connecteurs se dessinent, puis les étiquettes, puis le token en mouvement, puis le changement d'état final. Une chose commence pendant que la précédente se calme (chevauchenement ~0.1-0.3s) ; jamais tout en même temps, jamais strictement l'une après l'autre.
  • Valeurs :
QuoiDepuisDuréeEase (GSAP / cubic-bezier)
Titreopacité 0, y 80.6spower3.out / .16,1,.3,1
Carteopacité 0, y 12, échelle .970.8s, stagger 0.12sexpo.out / .16,1,.3,1
Tracé du connecteurdashoffset L+40.7s, stagger 0.1-0.3spower2.inOut / .65,0,.35,1
Pointe de flècheopacité 00.2s, quand la ligne se terminelinéaire
Étiquette de ligneopacité 0, y 40.5spower3.out
Trajet du tokenle long de la ligne1.0spower2.inOut
Échange de valeurancien : y -8, blur 3px, sortie 0.35s ; nouveau : y 8, blur 3px, entrée 0.5spower2.in / power3.out
  • Animez seulement transform, opacity, filter: blur et les stroke-dashoffset SVG.
  • Jamais à partir de scale(0) ; commencez à .97. Pas de rebond, pas de dépassement, pas d'élasticité. La seule exception : un petit pop back.out(1.6) pour une marque "non".
  • N'animez jamais un texte que le lecteur doit lire pendant qu'il bouge ; laissez-le atterrir, puis déplacez la chose suivante.
  • Métaphore physique quand elle convient : si la chose est une lettre, une facture ou une carte, déplacez-la comme l'objet réel.

Bibliothèques

Choisissez la bibliothèque en fonction de ce qu'est l'image, avant d'écrire du HTML. Réinventer ce qu'une bibliothèque fait déjà (un layout de force, une formule mathématique, un surlignage de code) est moins beau et plus cassant.

L'image estUtilisezPourquoi
Cartes et flèches, un flux, une séquence d'étapesCartes HTML + superposition SVG + timeline GSAPContrôle total du style ; GSAP ordonne les étapes
Une courte entrée, une liste qui apparaîtanimate de Motion + stagger, ou @keyframes CSSMoins de code qu'une timeline
Un graphe avec de nombreux nœuds dont vous ne pouvez pas choisir les positions à la mainelkjs (layout en couches) ou d3-force, puis dessinez dans notre styleLe calcul de layout est difficile à faire correctement à la main
Un vrai graphique (axes, de nombreux points, une échelle)d3 (échelles, axes, formes) stylisé à la mainChart.js seulement pour un barre/ligne rapide ; restylez ses valeurs par défaut
Maths, formulesKaTeXUn vrai composition mathématique
Codehighlight.js avec le thème github, police 15pxCouleurs lisibles sur fond blanc
Beaucoup de particules, une simulation, de la physique<canvas> sur rAF, piloté par performance.now()Le DOM est trop lent pour des centaines d'éléments
Quelque chose en 3Dthree.js (module ES + importmap)Seulement quand la profondeur est le sujet
Une sensation "idée vague / esquisse"rough.jsLignes dessinées à la main intentionnellement

Jamais Mermaid pour les explicateurs : son apparence par défaut combat ce style. Utilisez elkjs pour la mise en page à la place.

Épinglés, tous vérifiés sur cdn.jsdelivr.net (préfixe https://cdn.jsdelivr.net/npm/) :

Mise en page asynchrone (elkjs, polices, KaTeX) : construisez la scène, puis démarrez la timeline. L'image finale est prise à duration_ms, donc le tout doit quand même finir à temps.

Pièges :

  • Motion : la keyframe de fin doit utiliser les mêmes fonctions de transformation que le début. ['translateY(12px) scale(.97)','none'] rend scale(0), donc l'élément disparaît. Écrivez 'translateY(0px) scale(1)'.
  • Dessin de ligne : jamais pathLength="1" ; le tween de décalage de GSAP l'ignore et la ligne apparaît d'un coup. Mesurez L=p.getTotalLength(), définissez strokeDasharray:"${L} ${L+4}", strokeDashoffset:L+4 (le +4 cache le point d'arrondi), tweenez le décalage vers 0. Un chemin pointillé ne peut pas être dessiné de cette façon ; fondez-le en entrée.
  • Insérez les SVG et étiquettes mesurés avant de démarrer l'animation, et mesurez avant toute transformation appliquée.
  • Scripts à la fin de <body> ; chargez la balise CDN avant le script en ligne.

Jamais

  • Dégradés, lueur, néon, glassmorphisme, ombres lourdes ou colorées.
  • Violet, ou plus d'une teinte d'accent. Arrière-plans colorés sur de grandes zones.
  • Emoji ou décoration par police d'icônes. Un petit SVG en ligne avec trait de 1.5px si une icône est vraiment nécessaire.
  • Tout encadré. Carte héros centrée. Une carte dans une carte.
  • Un canvas étiré en pleine largeur avec le contenu flottant au milieu.
  • Flèches qui se croisent, lignes qui touchent les cartes, étiquettes qui chevauchent les lignes.
  • Légendes qui répètent le titre. Plus de ~12 mots de prose à l'intérieur de l'image.
  • Texte sous 16px, ou une police autre que celle ci-dessus, dans un expliqueur.

Après le rendu, lisez le PNG et vérifiez : espaces, chevauchements, texte coupé, côté droit vide.

Squelette

<style>/* tokens ci-dessus */ h2{font-size:26px;font-weight:700;letter-spacing:-.01em;margin:0 0 32px}
.row{position:relative;display:flex;gap:112px;width:max-content}
.node{padding:14px 18px;border:1px solid var(--line);border-radius:10px}
.node small{display:block;color:var(--muted);font-size:16px}
.hot{border-color:var(--accent)} svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
path{fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}</style>
<h2>Un cache hit contourne la base de données</h2>
<div class="row" id="row">
  <div class="node" id="a">Requête<small>GET /user/42</small></div>
  <div class="node hot" id="b">Cache<small>Redis, TTL 5 min</small></div>
  <svg id="s"></svg>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>
const R=row.getBoundingClientRect();
function link(p,q,color){ const a=p.getBoundingClientRect(),b=q.getBoundingClientRect();
  const y=a.top+a.height/2-R.top, x1=a.right-R.left+8, x2=b.left-R.left-8;
  s.insertAdjacentHTML('beforeend',`<path class="l" stroke="${color}" d="M${x1} ${y}H${x2}"/><path class="h" opacity="0" stroke="${color}" d="M${x2-5} ${y-4}l5 4-5 4"/>`); }
link(a,b,'#3b7a57');
s.querySelectorAll('.l').forEach(p=>{const L=p.getTotalLength();gsap.set(p,{strokeDasharray:`${L} ${L+4}`,strokeDashoffset:L+4})});
gsap.timeline()
  .from('h2',{opacity:0,y:8,duration:.6,ease:'power3.out'})
  .from('.node',{opacity:0,y:12,scale:.97,duration:.8,ease:'expo.out',stagger:.12},.2)
  .to('.l',{strokeDashoffset:0,duration:.7,ease:'power2.inOut'},1)
  .to('.h',{opacity:1,duration:.2},1.6);
</script>

Appelez avec width ≈ 560, rows: 10, duration_ms: 2200.

Skills associés