Communitygithub.com

anatems1/tidyfigs

Créez des figures draw.io / diagrams.net éditables et prêtes pour publication académique, avec trois modes : (A) IMAGE → convertit une image matricielle en objets draw.io natifs ; (B) TEXTE → transforme du texte ou des équations LaTeX en trois prototypes de figures ; (C) AMÉLIORATION → interroge l'utilisateur puis peaufine un fichier .drawio pour une revue cible.

Qu'est-ce que tidyfigs ?

Ce skill permet aux utilisateurs de générer des figures académiques de haute qualité et entièrement éditables à l'aide de draw.io / diagrams.net. Il offre trois modes principaux : le mode A convertit des images matricielles (PNG, JPG, WebP) en fichiers .drawio natifs, le mode B transforme du texte ou des équations LaTeX en trois prototypes de figures parmi lesquels l'utilisateur peut choisir, et le mode C améliore un fichier .drawio existant pour le rendre prêt pour une publication académique (taille d'impression, polices, couleurs, LaTeX). Le skill repose sur un script de construction Python (build script) qui stocke chaque coordonnée, rôle et taille, permettant une régénération et un rethème faciles. Il privilégie l'utilisation de rôles sémantiques (couleurs, polices, épaisseurs) via des thèmes YAML/TOML/JSON, évite le pixellisation des textes et assure une vérification visuelle après chaque construction. Les plateformes supportées incluent Claude Code, Cursor et Codex. Le processus est itératif et méthodique, avec des étapes de mesure, planification, thème, construction, rendu et comparaison jusqu'à ce que l'aperçu corresponde à la source.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/anatems1/tidyfigs/tree/HEAD/skills/tidyfigs

Demander à votre IA préférée

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

Documentation

Figures draw.io éditables pour articles académiques

Vous construisez des figures en tant qu'objets draw.io natifs à partir d'un script de construction Python (l'artefact de référence : chaque coordonnée, rôle et taille y vit, de sorte que la figure puisse être régénérée et rethématisée). Ne tracez jamais de pixels, ne pixellisez jamais de texte. Détails pour chaque appel et règle : REFERENCE.md. Modèles à copier : EXAMPLES.md.

Exécution des outils

Tout le code tient dans un seul fichier. T ci-dessous signifie python drawio_toolkit.py :

T <outil> [args]        # ex. T lint_drawio fig.drawio --theme theme.yaml   (tout outil : --help)
T unpack ./tidyfigs        # optionnel : dossier normal scripts/ assets/ examples/ ; puis python scripts/<outil>.py

En Python : import drawio_toolkit; drawio_toolkit.setup() → from drawio_kit import Diagram, from figlib import *, from drawio_doc import Doc. Les scripts de construction générés trouvent la bibliothèque par eux-mêmes.

Pas d'exécution de code disponible ? Suivez quand même la même méthode : écrivez le script de construction (ou, pour les petites figures, le XML draw.io directement — RÉFÉRENCE §14) pour que l'utilisateur l'exécute, et demandez-lui l'aperçu/le résultat de lint ou des captures d'écran au lieu de les visualiser vous-même.

Choisir le mode

EntréeModeSortie
image matricielle à recréerA image<img>.drawio + <img>#drawio.png (300 dpi) à côté de l'image
texte / section d'article / équationB texte3 prototypes → l'utilisateur choisit → <nom>.drawio
un fichier .drawio existant à rendre prêt pour publicationC amélioration<nom>#ENHANCED.drawio + exports PDF/SVG/PNG

A ou B est souvent suivi de C. Demandez quel mode seulement si la demande est vraiment ambiguë.

Règles partagées (tous les modes)

  • Rôles de thème uniquement. Les couleurs, polices, tailles, traits, opacités proviennent d'un thème YAML/TOML/JSON (fill="primary", size="body", sw="thick", fill_opacity="tint"). Les teintes = rôle existant + rôle d'opacité, pas un nouvel hex. Besoin d'une nouvelle couleur ? Ajoutez un rôle sémantique (highlight, chunk_b) et dites-le à l'utilisateur. Lint signale toute valeur hors thème ; les versions finales n'en ont aucune.
  • Régularisez vers l'intention : les éléments homologues obtiennent des tailles identiques, les lignes/colonnes un seul écart (row, row_widths, fit_row, column, grid_boxes), les bords partagés une seule coordonnée ; centrez les étiquettes sur ce qu'elles étiquettent (x + w/2). Ignorez le bruit de ±1 px.
  • Attachez les connecteurs avec src/tgt (+ fractions exit/entry) chaque fois qu'une ligne touche une forme ; pts liste uniquement ce que draw.io ne peut pas calculer (départ libre, waypoints, fin libre). Points libres uniquement pour les séparateurs, les axes de graphiques, les vecteurs non attachés.
  • Bords courbes (route="curved", flex_arrow, cycle) : les waypoints sont des points de contrôle ; la courbe passe par les points médians entre waypoints consécutifs.
  • Ordre Z = ordre de création (le dernier au-dessus) : canevas → panneaux → remplissages → formes → connecteurs → texte → annotations. Groupez les éléments qui bougent ensemble (with d.group("tile")).
  • Identifiants stables sur les sommets importants (nécessaires pour les bords, lint lisible).
  • Balisage du texte : **gras** *italique* __souligné__ {rôle|couleur} \n \* ; LaTeX en ligne \( … \) ; mathématiques d'affichage via d.equation(r"...") (MathJax natif, éditable). raw=True passe le HTML.
  • Vérifiez en regardant : après chaque construction, visualisez le(s) aperçu(s) PNG avec votre outil d'image ; les chiffres (lint, scores, audits) guident, la vérification visuelle décide. L'aperçu approxime draw.io : emoji = carrés gris, cylindres/documents = rectangles, pas de petites capitales, mathématiques via mathtext.
  • Hygiène de l'espace de travail : scripts temporaires, sondes et recadrages vont dans <workdir>/scratch/, jamais à côté des fichiers de l'utilisateur.
  • Valeurs par défaut académiques : fond blanc, pas de titre dans la figure (rédigez une légende à la place), ≤ 3 teintes + teintes, la couleur n'est jamais le seul encodage, une famille de polices, ≤ 6–7 rôles de taille, ≤ ~25 éléments de texte.

Mode A — image → draw.io éditable

Méthode : mesurer → planifier → thématiser → script de construction → rendre → comparer → corriger, jusqu'à ce que l'aperçu corresponde à la source dans la disposition. Les coordonnées sont des pixels de l'image source mesurés sur la grille réelle (estimer une vue redimensionnée est la cause n°1 des mauvaises conversions).

A0 Triage (définit l'effort ; lisez d'abord l'exemple le plus proche dans EXAMPLES.md) :

NiveauRessemble àTechniques principalesItérationsScore final
1 simpleboîtes, étiquettes, flèches droites/coudées, 1–3 panneauxrect, text, edge attaché, row2–3≥ 0.88
2 grille/tableau de bordtuiles avec icônes, colonnes, mini-flux, pucespanel, groupes, fit_row/grid_boxes, icon, bords orthogonaux3–5≥ 0.88
3 graphique/géométriqueaxes, vecteurs, points, cercles, flèches ondulées, étiquettes pivotéesdot, circle, ancres, flex_arrow, bords courbes, rotation3–6≥ 0.85
4 complexesurfaces 3D, maillages, photos, nuages de points denses, calloutssurface_mesh, polygon, image_crop, scatter_*, callout, calques Z5–10≥ 0.78

A1 Échafaudage + inspection : T new_build images/fig.png [--theme user.yaml] [--scale 1] crée images/fig_drawio_work/ (build.py, theme.yaml, NOTES.md, inspect/, iterations/, scratch/, history.json ; gardez-le). Lisez inspect/summary.md et visualisez source.grid*.png (positions), source.boxes.png/.json (boîtes englobantes exactes + couleurs médianes — utilisez-les directement), source.ocr.png/.json (texte + taille de police : utilisez est_px_if_regular/bold ajusté à la largeur, choisissez en regardant), source.palette.png (couleurs → rôle le plus proche, ΔE). L'échafaudage pré-remplit les boîtes détectées dans build.py — affinez-les. Zoomez n'importe quelle région : T inspect_image zoom SRC --box x0 y0 x1 y1 --factor 3 --step 10 ; sondez les caractéristiques fines/légères numériquement (T inspect_image probe SRC --box … ou numpy, RÉFÉRENCE §6.1). L'OCR peut mal lire et le détecteur fusionne les formes qui se touchent — vérifiez toujours visuellement.

A2 Plan dans NOTES.md : inventoriez région par région dans l'ordre Z. Décidez par élément : sommet natif (boîtes, panneaux, pilules, cercles, losanges, cylindres) · texte natif (tout texte, toujours) · edge attaché (connexions) · edge libre (axes, séparateurs) · flex_arrow (large/ondulé) · dots dans un groupe (nuage de points ≤ ~400) · polygon/svg_layer/surface_mesh (blobs, faisceaux, maillages, 3D) · image_crop (photos, textures, logos uniquement — reconstruisez leurs étiquettes nativement par-dessus) · forme de bibliothèque ou icône icon (icônes ; dites lesquelles). Enregistrez chaque décision non native pour le rapport.

A3 Thème : couleurs/polices de l'utilisateur → rôles, mappez chaque couleur source au rôle le plus proche ; sinon, les couleurs dominantes de la source dédupliquées en ≤ 6–8 rôles. Regroupez les tailles OCR en ≤ 6–7 rôles de taille (même niveau visuel ⇒ même rôle). Famille la plus proche disponible sur le Web (Helvetica/Arial ; Times New Roman pour le sérif de style LaTeX) ; google: true pour Roboto/Inter. Mesurez l'épaisseur du trait sur un zoom.

A4 Écrivez build.py (Diagram.from_source est pré-câblé ; API complète RÉFÉRENCE §2) :

pid, (cx, cy, cw, ch) = d.panel(52, 110, 620, 570, "**AUTO-ENCODAGE**", header_h=70, header_fill="primary",
                                header_color="background", title_size="heading")
for (x, y, w, h), t in zip(d.row_widths(182, 336, [97, 138, 97, 97], 62, gap=13), ["[A]", "[MASQUE]", "[C]", "[D]"]):
    d.rect(x, y, w, h, t, fill="token", stroke="text", rounded=4, size="body", id="tok_" + t.strip("[]"))
d.rect(275, 455, 170, 62, "**Encodeur**", fill="primary", color="background", rounded=4, id="enc")
d.edge([], src="enc", tgt="tok_MASQUE", sw="thick", exit=(.5, 0), entry=(.5, 1))
d.edge([(108, 486)], tgt="enc", entry=(0, .5))                     # départ libre, fin attachée
d.text("Dimension 2", 365, 144, size="small", rotation=-90)
d.image_crop((49, 199, 143, 309), border="text")                   # photo copiée depuis la source

Le contenu aléatoire (nuage de points) utilise une seed fixe et des rectangles de garde autour des étiquettes. > ~600 sommets → fusionnez les marques décoratives en un svg_layer. Petites sources → --scale 2 pour que le texte ≥ 10 px.

A5 Itérez : T iterate images/fig_drawio_work --note "ce qui a changé" = construire → rendre → comparer → lint → instantané + historique. Visualisez iter_NN_side.png (tout : formulation, tailles, poids, habillage), iter_NN_edges.png (rouge = source uniquement, cyan = aperçu uniquement ; déplacez jusqu'à ce que les paires fusionnent), iter_NN_heat.png + pires cellules (zoomez celles-ci ensuite). Travaillez en passes : (1) canevas, panneaux, grilles → (2) formes accrochées aux boîtes détectées et régularisées → (3) chaque connecteur attaché avec des ports → (4) rôles de police, poids, centrage, valign → (5) polissage des différences de bords. Changez quelques éléments liés par itération ; si le score baisse, annulez. Arrêtez quand : chaque élément de l'inventaire est présent (relisez la source région par région), lint 0 erreurs et pas d'avertissements de débordement/chevauchement/hors thème, côte à côte montre aucun mauvais placement ou mauvais texte, score stabilisé (< 0.005 de gain sur 2 itérations). Si le CLI draw.io existe : une finale T render_preview OUT --engine drawio.

A6 Finalisation : images/fig.drawio est la dernière construction ; exportez T render_preview images/fig.drawio -o "images/fig#drawio.png" --dpi 300. Le dossier d'images contient uniquement source, .drawio, #drawio.png (+ le répertoire de travail). Rapport : chemins ; natif vs intégré (photos, calques SVG, espaces réservés d'emoji) ; rôles utilisés/ajoutés ; écarts connus ; fautes de frappe de la source conservées ; comment re-thématiser (éditer theme.yaml → python build.py) et redimensionner.


Mode B — texte → trois prototypes de figures éditables

Lisez le passage, inventoriez ses affirmations, construisez trois familles de figures différentes, vérifiez-les, présentez une feuille côte à côte ; l'utilisateur choisit ; vous finalisez.

Emplacement de sortie : fichier drafts/methods.md → drafts/methods_figures/ ; texte collé → ./figures/<slug>/ ; entrée multi-section/longue → un sous-dossier par passage p1_<slug>/ … ; un dossier nommé par l'utilisateur → exactement celui-là (--out-dir). Dites le chemin à l'utilisateur. Un thème partagé par tous les passages (--theme ou éditer theme.yaml dans la racine de sortie).

B1 Échafaudage + analyse : T new_figures drafts/methods.md [--theme t.yaml] [--split|--whole] [--passages 1,3] ou T new_figures --text "<passage>" --name rag_pipeline. Imprime par passage : nombre de mots, équations, indices de structure, trois familles suggérées. ≤ 350 mots sans titres = un passage. Pas de structure digne d'une figure (pur récit) ? Dites-le au lieu de forcer des figures.

B2 Inventaire (NOTES.md) : entités, étapes ordonnées (avec leurs verbes), relations (direction + verbe), quantités avec unités, qualificatifs, conclusions — chacun avec une courte citation. Confirmez les familles (RÉFÉRENCE §7) : par défaut = trois mises en page de la structure dominante (détaillée / aperçu compact / angle alternatif); forte deuxième structure → deux + un ; équations → le trio d'équations sauf si incidentelles. Les trois doivent différer en topologie (couloirs / pile / radial / matrice / graphique / plaque), pas en style. Pour les passages mathématiques, scientifiques, algorithmiques, préférez les démonstrations actives (calcul matriciel rempli, espaces métriques/coordonnées continus, plaques bayésiennes, DAG causaux) aux cartes à puces statiques.

B3 Écrivez build.py — trois constructeurs, chacun obtient un Diagram frais de sa taille de canevas :

from figlib import *
INFERRED = ["v1: les évaluations ordinales interprètent la formulation qualitative du passage"]   # rapporté à l'utilisateur
ALLOWED_TERMS = ["couche"]                # mots structurels, pas d'affirmations
LINT_IGNORE = []                         # avertissements acceptés intentionnellement (sous-chaîne)
def v1(d):                               # pipeline en couloirs
    lane(d, 20, 20, 1060, 175, "Indexation hors ligne")
    chain(d, ["Rapports d'inspection\n(numérisés)", "OCR\nvers texte", "Découpage\nsémantique"], 80, 78, 140, 60,
          shapes=["document", None, None], ids=["rep", "ocr", "chk"])
VARIANTS = [dict(key="v1", name="pipeline_couloirs", size=(1100, 400), build=v1,
                 about="une ligne pour la feuille", caption="Légende provisoire dans les mots du passage."), ...]

Règles : rôles de thème uniquement, même catégorie = même style dans les trois ; homologues partagent tailles et un écart (aides, pas de nombres ajustés à la main) ; connecteurs attachés, rétroaction en pointillés/secondaire ; ≤ ~25 éléments de texte, < ~150 sommets (sinon divisez en deux figures) ; pas de titre dans la figure — écrivez caption ; étiquettes dans la formulation du passage (raccourcissez par suppression, pas par synonyme ; conservez les qualificatifs, chiffres, unités, acronymes tels quels). Dispositifs interprétatifs (évaluations, frontières, "meilleur ajustement", ordres d'axes, faits mathématiques non présents dans le texte) uniquement s'ils sont listés dans INFERRED.

B4 Prototype, inspectez, corrigez (≥ 2 tours) : T prototype <répertoire passage> [--only v2] --note "…" construit les trois, rend, lint, exécute la vérification de fidélité, écrit prototypes.png/.md, enregistre err/warn/miss. Visualisez chaque PNG et la feuille. Corrigez chaque avertissement lint ou ajoutez un LINT_IGNORE délibéré ; résolvez chaque mot NON DANS LE PASSAGE (reformulez avec le terme du passage · ALLOWED_TERMS si structurel · INFERRED si interprétation). Vérifiez ce que lint ne peut pas : flèches croisant des étiquettes, coins encombrés, hiérarchie faible, espacement blanc déséquilibré, deux prototypes trop similaires, direction de chaque flèche par rapport à l'inventaire. Fait à 0/0/0 (ou avertissements acceptés) et propre en taille réelle.

B5 Présentez : montrez prototypes.png ; par prototype une ligne sur son accent, sa légende provisoire, ses éléments INFERRED ; signalez les bizarreries de la source (fautes de frappe, noms incohérents) plutôt que de les corriger en silence. Demandez à l'utilisateur de choisir (ou de demander des modifications / une combinaison → éditer build.py, ré-exécuter).

B6 Finalisation : T finalize <répertoire passage> --pick v2 [--name rag_pipeline] [--clean] → <nom>.drawio (+ .png) et CHOSEN.md (légende, inféré). --clean supprime les autres prototypes mais garde _work/. Proposez le mode C pour le polissage spécifique à la revue.


Mode C — améliorer un fichier .drawio pour publication

Une passe délibérée : comprendre le travail de la figure → mesurer à la taille d'impression → la changer pour servir ce travail → vérifier → exporter. Ne modifiez jamais avant l'entretien.

C1 Début : T start_enhance chemin/FIG.drawio [--source-image] [--text] [--artifacts DIR] [--theme]. Il découvre le contexte (répertoire de travail du mode A : image source, build.py, theme, NOTES ; dossier de passage du mode B : passage.md, build.py VARIANTS, CHOSEN.md, caption, INFERRED), détecte les modifications manuelles après génération, recommande une route, audite "avant", écrit <stem>_enhance_work/ (context.md, before_audit.md, brief.yaml, questions.md, theme.yaml, build_enhanced.py si

Skills associés