Communitygithub.com

ethanweber/posterskill

Génère un poster de conférence au format HTML à partir d'un article et d'un site web de projet, imprimable en PDF

Qu'est-ce que posterskill ?

Cette compétence pour agents IA génère automatiquement un poster de conférence professionnel au format HTML, conçu pour être imprimé en PDF sans gaspillage d'espace. Elle prend en entrée le code source LaTeX d'un article (situé dans le dossier `overleaf/`), l'URL du site web du projet (pour extraire figures, logos, et informations), et des posters de référence (dans `references/`) pour en reproduire le style visuel (couleurs, typographie, mise en page). Le poster généré est une application React autonome dans un seul fichier HTML (sans étape de build, React et Babel chargés via CDN), avec un éditeur interactif où l'utilisateur peut réorganiser les cartes, redimensionner les colonnes et lignes, ajuster la police, et exporter la configuration en JSON pour la réinjecter dans l'agent. La compétence inclut une optimisation automatique avec Playwright pour minimiser les blancs, la génération de codes QR, et l'intégration facultative avec GitHub. Elle fonctionne sur n'importe quel système avec Python, Playwright, et `sips` (macOS) ou équivalent.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ethanweber/posterskill/tree/HEAD/.claude/skills/make-poster

Demander à votre IA préférée

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

Aperçu

Depuis le README du skill

posterskill preview

Documentation

Générateur de Poster de Conférence (HTML)

Générez un poster HTML professionnel. Notes utilisateur : $ARGUMENTS

Le poster est un éditeur interactif basé sur React — un seul fichier HTML autonome dans le répertoire poster/. Aucune étape de build nécessaire (React/Babel chargés via CDN). L'utilisateur peut ajuster visuellement la mise en page dans son navigateur, puis exporter la configuration vers Claude pour d'autres modifications.

Structure du dossier du projet

<projet>/
├── overleaf/              # Source de l'article depuis Overleaf
│   ├── paper.tex
│   ├── figures/
│   └── ...
├── references/            # Posters de référence pour l'adaptation stylistique
│   └── (tout format : pdf, png, jpg, html, pptx, ...)
├── poster/                # GÉNÉRÉ : site web autonome du poster
│   ├── index.html         # Le poster (application React)
│   ├── poster-config.json # Configuration de la mise en page (colonnes, ordre des cartes, hauteurs, échelle de police)
│   ├── logos/             # Logos des institutions
│   ├── teaser.png         # Figures copiées/converties
│   ├── qr.png             # Code QR de la page du projet
│   ├── qr-posterskill.png # Code QR de Posterskill
│   └── ...
└── .claude/skills/make-poster/
  • overleaf/ contient la source de l'article. Lisez le fichier .tex principal et tous les fichiers qu'il inclut avec \input{}.
  • references/ contient des exemples de posters montrant le style visuel préféré de l'utilisateur. Lisez/visualisez TOUS les fichiers de ce dossier pour reproduire leur langage de conception.
  • poster/ est la sortie générée — un site web autonome. Toutes les figures et ressources se trouvent aux côtés de index.html pour que les chemins relatifs fonctionnent simplement.

Entrées

  1. Source de l'article - Située dans overleaf/. Demandez à l'utilisateur quel fichier .tex est le principal à lire (par exemple, paper.tex, main.tex). Lisez-le ainsi que tous les fichiers qu'il inclut avec \input{}.
  2. Site web du projet - Demandez l'URL à l'utilisateur si elle n'est pas déjà connue. Récupérez-la avec WebFetch pour extraire les informations sur les auteurs, les images hébergées et les liens.
  3. Posters de référence - Découverts automatiquement dans references/. Visualisez tous les fichiers et reproduisez leur style.
  4. Site web de l'auteur (optionnel) - Récupérez-le avec WebFetch et extrayez les signaux de conception (palette de couleurs, typographie, logos). Téléchargez les logos institutionnels depuis le site de l'auteur avec Playwright (curl peut échouer à cause des redirections) : page.request.get(url) pour télécharger les octets bruts.
  5. Exigences de formatage - Demandez les dimensions du poster, l'orientation, le nombre de colonnes.
  6. Dépôt Git (optionnel) - Demandez à l'utilisateur s'il a un dépôt GitHub pour pousser le poster.

Si l'utilisateur ne spécifie pas le formatage, demandez-lui avant de continuer. Ne supposez pas de valeurs par défaut pour les dimensions, l'orientation ou le nombre de colonnes.

Processus

Étape 0 : Analyser les références de style

Cherchez dans references/ tout fichier PDF, PNG ou image. Convertissez les PDF en PNG (sips -s format png sur macOS). Visualisez chacun et notez le style visuel — mise en page, couleurs, typographie, styles de cartes, placement des figures. Adaptez le style de référence — ne choisissez pas un thème sombre si la référence est claire, etc.

Étape 1 : Extraire le contenu de la source de l'article

Demandez à l'utilisateur quel fichier .tex lire. Extrayez : titre, auteurs, affiliations, résumé (2-3 phrases), méthode clé, résultats (tableaux + figures), équations clés (1-2 maximum), conclusion.

Étape 2 : Récupérer le site web du projet

Utilisez WebFetch pour obtenir les noms des auteurs, affiliations, URL des figures, URL du projet pour le QR, liens vers le code/arxiv/vidéo.

Étape 3 : Rassembler les ressources dans poster/

Figures : Copiez depuis overleaf/figures/, en convertissant les PDF en PNG à haute résolution :

sips -s format png input.pdf --out poster/output.png -Z 3000

Images du site web : Téléchargez des images de meilleure qualité depuis le site web du projet avec Playwright (pas curl — de nombreux sites redirigent) :

resp = page.request.get(url)
with open('poster/filename.png', 'wb') as f:
    f.write(resp.body())

Logos : Téléchargez les logos institutionnels depuis le site web personnel de l'auteur avec Playwright. Sauvegardez dans poster/logos/. Le modèle les inverse automatiquement en blanc pour l'en-tête.

Codes QR : Générez et sauvegardez :

curl -sL -o poster/qr.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=PROJECT_URL"
curl -sL -o poster/qr-posterskill.png "https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=https://github.com/ethanweber/posterskill"

Étape 4 : Mesurer les proportions des images

Ceci est crucial pour éliminer les espaces blancs. Mesurez chaque image :

sips -g pixelWidth -g pixelHeight poster/*.png poster/*.jpg

Ensuite, assignez les images aux colonnes en fonction du rapport hauteur/largeur :

  • Images larges (>2:1 ratio, par exemple teaser, architecture) : placez dans la colonne la plus large
  • Images carrées (~1:1 ratio) : placez dans les colonnes étroites
  • Images portrait (<1:1 ratio) : placez dans la colonne la plus étroite

Cela évite le problème numéro 1 des espaces blancs : les images larges dans des cellules étroites (ou vice versa) laissant de grands vides.

Étape 5 : Générer le HTML du poster

Utilisez le modèle situé à ${{CLAUDE_SKILL_DIR}}/template.html comme point de départ. Le modèle est une application React avec :

Architecture :

  • CARD_REGISTRY — définit le contenu de chaque carte (titre, couleur, corps JSX)
  • DEFAULT_LAYOUT — définit la structure des colonnes et l'ordre des cartes
  • DEFAULT_LOGOS — logos institutionnels pour l'en-tête
  • L'état React gère la mise en page, avec persistance dans localStorage
  • window.posterAPI expose des fonctions pour le contrôle programmatique

Éléments clés à personnaliser :

  1. Mettez à jour CARD_REGISTRY avec le contenu de l'article (chaque section est une carte)
  2. Mettez à jour DEFAULT_LAYOUT avec les assignations de colonnes optimisées par rapport hauteur/largeur
  3. Mettez à jour DEFAULT_LOGOS avec les logos institutionnels de l'utilisateur
  4. Mettez à jour DEFAULT_FONT_SCALE (commencez à 1.3, l'utilisateur peut ajuster avec les boutons A-/A+)
  5. Mettez à jour l'en-tête (titre, auteurs, affiliations, badge de conférence, codes QR)
  6. Mettez à jour @page { size: LARGEURmm HAUTEURmm; } et body { width: LARGEURmm; height: HAUTEURmm; } pour les dimensions du poster
  7. Mettez à jour la fonction posterAPI fit() avec les mêmes dimensions

Motifs de contenu des cartes :

  • Carte de figure : <div className="fig"><div className="fig-wrap"><img src="file.png" alt="..." /></div><div className="cap"><b>Titre de la légende.</b> Description.</div></div>
  • Carte de texte : <div className="hl"><p>Texte en surbrillance</p></div><ul><li>Point 1</li></ul>
  • Carte de tableau : <table><thead>...</thead><tbody>...</tbody></table> avec className="best" sur les cellules gagnantes
  • Carte d'équation : <div className="eq">{'$Équation LaTeX$'}</div> (échappez les backslashes dans JSX)

Règles CSS critiques pour zéro espace blanc :

  • Les images DOIVENT utiliser width:100%; height:100%; object-fit:contain (PAS max-width/max-height — celles-ci empêchent l'agrandissement)
  • Chaque colonne doit toujours avoir une carte avec grow: true (flex:1) qui remplit l'espace restant
  • La fonction isCardGrow() garantit cela automatiquement — si aucune carte n'a grow, la dernière carte l'obtient

Mise à l'échelle de la zone d'affichage :

  • Utilisez translate() + scale() sur body pour centrer et adapter le poster à n'importe quelle zone d'affichage du navigateur
  • transform-origin: top left est critique
  • @media print doit définir transform: none !important pour une résolution d'impression correcte
  • getBoundingClientRect() retourne des valeurs MISES À L'ÉCHELLE — divisez toujours par currentScaleRef.current dans les gestionnaires de redimensionnement

Étape 6 : Optimiser automatiquement la mise en page avec Playwright

Après la génération, utilisez Playwright pour mesurer les espaces blancs et trouver les largeurs de colonnes optimales :

from playwright.sync_api import sync_playwright
import os

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={'width': 3200, 'height': 2260})
    page.goto('file://' + os.path.abspath('poster/index.html'))
    page.wait_for_load_state('networkidle')
    page.wait_for_timeout(3000)

    # Mesurer les espaces blancs
    waste = page.evaluate('window.posterAPI.getWaste()')
    print(f"Espace total perdu : {waste['total']}px")
    for d in waste['details']:
        print(f"  {d['card']}: H={d['wasteH']} W={d['wasteW']} ({d['pct']}%)")

    # Essayer différentes largeurs de colonnes pour minimiser le gaspillage
    best_waste = waste['total']
    best_c1, best_c3 = 300, 230
    for c1 in range(200, 350, 10):
        for c3 in range(160, 280, 10):
            page.evaluate(f'window.posterAPI.setColumnWidth("col1", {c1})')
            page.evaluate(f'window.posterAPI.setColumnWidth("col3", {c3})')
            page.wait_for_timeout(30)
            w = page.evaluate('window.posterAPI.getWaste().total')
            if w < best_waste:
                best_waste = w
                best_c1, best_c3 = c1, c3

    # Appliquer le meilleur et faire une capture d'écran
    page.evaluate(f'window.posterAPI.setColumnWidth("col1", {best_c1})')
    page.evaluate(f'window.posterAPI.setColumnWidth("col3", {best_c3})')
    page.wait_for_timeout(500)
    page.screenshot(path='/tmp/poster_screenshot.png')

    # Essayer aussi d'échanger des cartes entre les colonnes
    page.evaluate('window.posterAPI.swapCards("cardA", "cardB")')
    # ... mesurer le gaspillage à nouveau ...

    browser.close()

Ensuite, lisez /tmp/poster_screenshot.png pour inspecter visuellement. Itérez plusieurs fois — prenez des captures d'écran, corrigez les problèmes, re-capturez jusqu'à ce que le poster ait un espace blanc minimal.

Après avoir trouvé les valeurs optimales, intégrez-les dans DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, etc. dans le HTML.

Étape 7 : Générer le PDF et vérifier

page.pdf(
    path='poster/poster.pdf',
    width='841mm', height='594mm',  # correspondre aux dimensions du poster
    margin={'top':'0','right':'0','bottom':'0','left':'0'},
    print_background=True
)

Convertissez le PDF en PNG et lisez-le pour vérifier qu'il s'affiche en pleine résolution :

sips -s format png poster/poster.pdf --out /tmp/poster_pdf_check.png -Z 3000

Étape 8 : Ouvrir et itérer avec l'utilisateur

Ouvrez le poster dans le navigateur :

open poster/index.html

Expliquez les contrôles d'édition à l'utilisateur :

  • Aperçu — basculez l'interface d'édition pour voir exactement comment il s'imprimera
  • A-/A+ — ajustez la taille de la police globalement
  • Faites glisser les séparateurs de colonnes (barres bleues verticales) — redimensionnez les colonnes à gauche/droite
  • Faites glisser les séparateurs de lignes (barres bleues horizontales) — redimensionnez les cartes vers le haut/bas dans les colonnes
  • Cliquez pour échanger — cliquez sur la poignée en losange d'une carte (devient orange), puis cliquez sur une autre pour les échanger
  • Déplacer/insérer — cliquez sur la poignée d'une carte, puis cliquez sur une zone de dépôt en pointillés orange pour l'y déplacer
  • Sauvegarder — télécharge poster-config.json
  • Copier la configuration — copie le JSON de mise en page dans le presse-papiers
  • Réinitialiser — restaurer les valeurs par défaut

Proposez proactivement des améliorations : Après avoir montré la première ébauche, suggérez des modifications spécifiques :

  • "La carte d'architecture du modèle a des espaces blancs — essayez de faire glisser le séparateur de ligne au-dessus vers le bas pour lui donner moins d'espace"
  • "La figure de complétion pourrait mieux paraître dans la colonne 2 car elle est plus large — essayez de cliquer sur son losange, puis de cliquer sur une zone de dépôt dans la colonne 2"
  • "Vous pourriez augmenter la taille de la police avec A+ quelques fois"

Encouragez la boucle de rétroaction : Dites à l'utilisateur :

Essayez de réorganiser le poster dans votre navigateur ! Lorsque vous êtes satisfait de la mise en page, cliquez sur Copier la configuration dans la barre d'outils en haut à droite et collez-la ici — j'intégrerai ces modifications dans les valeurs par défaut pour qu'elles persistent.

  • Sauvegarder — télécharge poster-config.json
  • Copier la configuration — copie le JSON de mise en page dans le presse-papiers pour le coller à Claude
  • Réinitialiser — restaurer les valeurs par défaut

Lorsque l'utilisateur colle un JSON de configuration, mettez à jour DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, DEFAULT_FONT_SCALE, et DEFAULT_LOGOS dans le HTML en conséquence. Écrivez-le également dans poster-config.json.

Étape 9 : Pousser vers GitHub (optionnel)

Si l'utilisateur fournit une URL de dépôt GitHub :

cd poster
git init
git remote add origin <URL_DÉPÔT>
git add .
git commit -m "Poster : <titre de l'article>"
git push -u origin main

Directives importantes

  • Pas d'espace blanc. C'est la priorité numéro 1. Utilisez l'assignation de colonnes basée sur le rapport hauteur/largeur, width:100%; height:100%; object-fit:contain sur les images, les cartes à croissance automatique, et l'optimiseur Playwright. Itérez jusqu'à ce que le gaspillage soit minimal.
  • Gardez le texte minimal. Les posters sont visuels — des puces, pas des paragraphes. Compréhension en 2 minutes.
  • Adaptez le style de référence. Si le poster de référence est clair/propre, n'utilisez pas un thème sombre. Reproduisez l'esthétique globale.
  • Mise à l'échelle de la police. Toutes les tailles de texte utilisent calc(Xpt * var(--font-scale)) pour que les boutons A-/A+ fonctionnent. Commencez avec --font-scale: 1.3 et laissez l'utilisateur ajuster.
  • CSS optimisé pour l'impression. @media print masque toute l'interface d'édition et définit transform: none !important. @page définit les dimensions exactes.
  • QR Posterskill. Incluez toujours un code QR pointant vers https://github.com/ethanweber/posterskill dans l'en-tête avec le label "Poster réalisé avec ma compétence Claude".
  • Pas de pied de page de remerciements. Gardez le poster propre — pas de pied de page par défaut.
  • Logos dans l'en-tête. Téléchargez les logos institutionnels depuis le site web de l'auteur, sauvegardez-les dans poster/logos/, et listez-les dans DEFAULT_LOGOS. Ils sont automatiquement inversés en blanc via le filtre CSS.
  • Autonome. Pas d'étape de build, pas de npm, pas de serveur. Un seul fichier HTML avec des dépendances CDN. Fonctionne lorsqu'il est ouvert directement en tant que file://.
  • Équations. Utilisez KaTeX (chargé via CDN). Échappez les backslashes dans les chaînes JSX : {'$\mathcal{E}$'}.

Gestion des figures

  • Copiez toujours les figures nécessaires dans poster/ — ne référencez pas les chemins overleaf/ dans le HTML.
  • Convertissez les PDF en PNG à haute résolution : sips -s format png input.pdf --out poster/output.png -Z 3000
  • Téléchargez les images du site web via page.request.get() de Playwright (pas curl — les sites web redirigent souvent).
  • Mesurez les rapports hauteur/largeur avec sips -g pixelWidth -g pixelHeight et assignez-les aux colonnes en conséquence.

Flux de travail utilisateur pour les mises à jour de configuration

L'utilisateur peut ajuster le poster dans son navigateur et partager les modifications :

  1. L'utilisateur clique sur "Copier la configuration" dans la barre d'outils
  2. L'utilisateur colle le JSON dans le chat
  3. Claude met à jour DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, DEFAULT_FONT_SCALE, DEFAULT_LOGOS dans index.html en conséquence
  4. Claude écrit également la configuration dans poster-config.json
  5. L'utilisateur actualise et clique sur "Réinitialiser" pour charger les nouvelles valeurs par défaut

API programmatique (window.posterAPI)

Disponible dans la console du navigateur ou via Playwright :

  • swapCards(id1, id2) — échange deux cartes (fonctionne entre les colonnes)
  • moveCard(cardId, targetColId, position) — déplace une carte vers une position spécifique
  • setColumnWidth(colId, widthMm) — définit la largeur d'une colonne (null pour flex)
  • ...

[truncated for translation]

Skills associés