Generador de Póster de Conferencia (HTML)
Genera un póster HTML profesional. Notas del usuario: $ARGUMENTS
El póster es un editor interactivo basado en React — un único archivo HTML autocontenido en el directorio poster/. No necesita paso de compilación (React/Babel se cargan vía CDN). El usuario puede ajustar visualmente la disposición en su navegador y luego exportar la configuración de vuelta a Claude para realizar más cambios.
Estructura de la carpeta del proyecto
<proyecto>/
├── overleaf/ # Código fuente del artículo desde Overleaf
│ ├── paper.tex
│ ├── figures/
│ └── ...
├── references/ # Pósters de referencia para igualar el estilo
│ └── (cualquier formato: pdf, png, jpg, html, pptx, ...)
├── poster/ # GENERADO: sitio web del póster autocontenido
│ ├── index.html # El póster (aplicación React)
│ ├── poster-config.json # Configuración de diseño (columnas, orden de tarjetas, alturas, escala de fuente)
│ ├── logos/ # Logos institucionales
│ ├── teaser.png # Figuras copiadas/convertidas
│ ├── qr.png # Código QR de la página del proyecto
│ ├── qr-posterskill.png # Código QR de Posterskill
│ └── ...
└── .claude/skills/make-poster/
overleaf/contiene el código fuente del artículo. Lea el archivo.texprincipal y cualquier archivo que incluya con\input{}.references/contiene pósters de ejemplo que muestran el estilo visual preferido del usuario. Lea/vea TODOS los archivos de esta carpeta para igualar su lenguaje de diseño.poster/es la salida generada — un sitio web autocontenido. Todas las figuras y activos se encuentran junto aindex.htmlpara que las rutas relativas funcionen sin problemas.
Entradas
- Código fuente del artículo - Ubicado en
overleaf/. Pregunte al usuario qué archivo.texes el principal (ej.,paper.tex,main.tex). Luego léalo junto con los archivos que incluya con\input{}. - Sitio web del proyecto - Pregunte al usuario la URL si no se conoce ya. Obténgalo con WebFetch para extraer información de autores, imágenes alojadas y enlaces.
- Pósters de referencia - Descubiertos automáticamente desde
references/. Vea todos los archivos allí y empareje su estilo. - Sitio web del autor (opcional) - Obténgalo con WebFetch y extraiga señales de diseño (paleta de colores, tipografía, logos). Descargue los logos institucionales del sitio del autor usando Playwright (curl puede fallar debido a redirecciones):
page.request.get(url)para descargar los bytes sin procesar. - Requisitos de formato - Pregunte por las dimensiones del póster, orientación y número de columnas.
- Repositorio Git (opcional) - Pregunte al usuario si tiene un repositorio de GitHub para subir el póster.
Si el usuario no especifica el formato, pregúntele antes de continuar. No asuma valores predeterminados para dimensiones, orientación o número de columnas.
Proceso
Paso 0: Analizar referencias de estilo
Busque en references/ archivos PDF, PNG o de imagen. Convierta los PDF a PNG (sips -s format png en macOS). Vea cada uno y observe el estilo visual — diseño, colores, tipografía, estilos de tarjetas, colocación de figuras. Empareje el estilo de referencia — no use un tema oscuro por defecto si la referencia es clara, etc.
Paso 1: Extraer contenido del artículo
Pregunte al usuario qué archivo .tex leer. Extraiga: título, autores, afiliaciones, resumen (2-3 oraciones), método clave, resultados (tablas + figuras), ecuaciones clave (1-2 máximo), conclusión.
Paso 2: Obtener el sitio web del proyecto
Use WebFetch para obtener nombres de autores, afiliaciones, URL de figuras, URL del proyecto para el código QR, enlaces al código/arxiv/video.
Paso 3: Reunir activos en poster/
Figuras: Copie desde overleaf/figures/, convirtiendo PDF a PNG en alta resolución:
sips -s format png input.pdf --out poster/output.png -Z 3000
Imágenes del sitio web: Descargue imágenes de mayor calidad del sitio web del proyecto usando Playwright (no curl — muchos sitios redirigen):
resp = page.request.get(url)
with open('poster/filename.png', 'wb') as f:
f.write(resp.body())
Logos: Descargue los logos institucionales del sitio web personal del autor usando Playwright. Guárdelos en poster/logos/. La plantilla los invierte automáticamente a blanco para el encabezado.
Códigos QR: Genere y guarde:
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"
Paso 4: Medir las relaciones de aspecto de las imágenes
Esto es crítico para eliminar espacios en blanco. Mida cada imagen:
sips -g pixelWidth -g pixelHeight poster/*.png poster/*.jpg
Luego asigne imágenes a columnas según su relación de aspecto:
- Imágenes anchas (>2:1 ratio, ej., teaser, arquitectura): colóquelas en la columna más ancha
- Imágenes cuadradas (~1:1 ratio): colóquelas en columnas estrechas
- Imágenes verticales (<1:1 ratio): colóquelas en la columna más estrecha
Esto evita el problema #1 de espacios en blanco: imágenes anchas en celdas estrechas (o viceversa) que dejan grandes huecos.
Paso 5: Generar el HTML del póster
Use la plantilla en ${{CLAUDE_SKILL_DIR}}/template.html como punto de partida. La plantilla es una aplicación React con:
Arquitectura:
CARD_REGISTRY— define el contenido de cada tarjeta (título, color, cuerpo JSX)DEFAULT_LAYOUT— define la estructura de columnas y el orden de tarjetasDEFAULT_LOGOS— logos institucionales para el encabezado- El estado de React gestiona el diseño, con persistencia en localStorage
window.posterAPIexpone funciones para control programático
Cosas clave para personalizar:
- Actualice
CARD_REGISTRYcon el contenido del artículo (cada sección es una tarjeta) - Actualice
DEFAULT_LAYOUTcon las asignaciones de columna optimizadas por relación de aspecto - Actualice
DEFAULT_LOGOScon los logos institucionales del usuario - Actualice
DEFAULT_FONT_SCALE(empiece en 1.3, el usuario puede ajustar con botones A-/A+) - Actualice el encabezado (título, autores, afiliaciones, insignia de conferencia, códigos QR)
- Actualice
@page { size: WIDTHmm HEIGHTmm; }ybody { width: WIDTHmm; height: HEIGHTmm; }para las dimensiones del póster - Actualice la función fit() de posterAPI con las mismas dimensiones
Patrones de contenido de tarjetas:
- Tarjeta de figura:
<div className="fig"><div className="fig-wrap"><img src="file.png" alt="..." /></div><div className="cap"><b>Título del pie.</b> Descripción.</div></div> - Tarjeta de texto:
<div className="hl"><p>Texto destacado</p></div><ul><li>Punto 1</li></ul> - Tarjeta de tabla:
<table><thead>...</thead><tbody>...</tbody></table>conclassName="best"en las celdas ganadoras - Tarjeta de ecuación:
<div className="eq">{'$Ecuación LaTeX$'}</div>(escape de barras invertidas en JSX)
Reglas CSS críticas para cero espacios en blanco:
- Las imágenes DEBEN usar
width:100%; height:100%; object-fit:contain(NO max-width/max-height — evitan el escalado ascendente) - Cada columna debe tener siempre una tarjeta con
grow: true(flex:1) que llene el espacio restante - La función
isCardGrow()garantiza esto automáticamente — si ninguna tarjeta tiene grow, la última tarjeta lo recibe
Escalado de ventana gráfica:
- Use
translate() + scale()en el body para centrar y ajustar el póster a cualquier ventana del navegador transform-origin: top leftes crítico@media printdebe establecertransform: none !importantpara una resolución de impresión correctagetBoundingClientRect()devuelve valores ESCALADOS — divida siempre porcurrentScaleRef.currenten los manejadores de redimensionamiento
Paso 6: Optimizar automáticamente el diseño con Playwright
Después de generar, use Playwright para medir espacios en blanco y encontrar anchos de columna óptimos:
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)
# Medir espacios en blanco
waste = page.evaluate('window.posterAPI.getWaste()')
print(f"Desperdicio total: {waste['total']}px")
for d in waste['details']:
print(f" {d['card']}: H={d['wasteH']} W={d['wasteW']} ({d['pct']}%)")
# Probar diferentes anchos de columna para minimizar desperdicio
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
# Aplicar el mejor y capturar pantalla
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')
# También probar intercambiar tarjetas entre columnas
page.evaluate('window.posterAPI.swapCards("cardA", "cardB")')
# ... medir desperdicio otra vez ...
browser.close()
Luego lea /tmp/poster_screenshot.png para inspeccionar visualmente. Itere varias veces — tome capturas de pantalla, corrija problemas, vuelva a tomar capturas hasta que el póster tenga un espacio en blanco mínimo.
Después de encontrar valores óptimos, intégrelos en DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, etc. en el HTML.
Paso 7: Generar PDF y verificar
page.pdf(
path='poster/poster.pdf',
width='841mm', height='594mm', # coincidir con las dimensiones del póster
margin={'top':'0','right':'0','bottom':'0','left':'0'},
print_background=True
)
Convierta el PDF a PNG y léalo para verificar que se renderiza a máxima resolución:
sips -s format png poster/poster.pdf --out /tmp/poster_pdf_check.png -Z 3000
Paso 8: Abrir e iterar con el usuario
Abra el póster en el navegador:
open poster/index.html
Explique al usuario los controles de edición:
- Vista previa — desactive la interfaz de edición para ver exactamente cómo se imprimirá
- A-/A+ — ajuste el tamaño de fuente globalmente
- Arrastrar divisores de columna (barras azules verticales) — redimensione columnas a izquierda/derecha
- Arrastrar divisores de fila (barras azules horizontales) — redimensione tarjetas arriba/abajo dentro de las columnas
- Haga clic para intercambiar — haga clic en el asa de diamante de una tarjeta (se vuelve naranja), luego haga clic en otra para intercambiarlas
- Mover/insertar — haga clic en el asa de una tarjeta, luego haga clic en una zona de destino naranja discontinua para moverla allí
- Guardar — descarga
poster-config.json - Copiar Config — copia el JSON de diseño al portapapeles
- Restablecer — restaura los valores predeterminados
Sugiera mejoras proactivamente: Después de mostrar el primer borrador, sugiera cambios específicos:
- "La tarjeta de arquitectura del modelo tiene algo de espacio en blanco — intente arrastrar el divisor de fila hacia abajo para darle menos espacio"
- "La figura de finalización podría verse mejor en la columna 2 ya que es más ancha — intente hacer clic en su diamante, luego haga clic en una zona de destino en la columna 2"
- "Podría aumentar el tamaño de fuente con A+ varias veces"
Fomente el ciclo de retroalimentación: Dígale al usuario:
¡Intente reorganizar el póster en su navegador! Cuando esté satisfecho con el diseño, haga clic en Copiar Config en la barra de herramientas superior derecha y péguelo aquí — incorporaré esos cambios en los valores predeterminados para que persistan.
- Guardar — descargar
poster-config.json - Copiar Config — copiar el JSON de diseño al portapapeles para pegarlo a Claude
- Restablecer — restaurar valores predeterminados
Cuando el usuario pegue un JSON de configuración, actualice DEFAULT_LAYOUT, DEFAULT_CARD_HEIGHTS, DEFAULT_FONT_SCALE y DEFAULT_LOGOS en el HTML para coincidir. También escríbalo a poster-config.json.
Paso 9: Subir a GitHub (opcional)
Si el usuario proporciona una URL de repositorio de GitHub:
cd poster
git init
git remote add origin <REPO_URL>
git add .
git commit -m "Póster: <título del artículo>"
git push -u origin main
Pautas importantes
- Sin espacios en blanco. Esta es la prioridad #1. Use asignación de columnas consciente de la relación de aspecto,
width:100%; height:100%; object-fit:containen imágenes, tarjetas de crecimiento automático y el optimizador de Playwright. Itere hasta que el desperdicio sea mínimo. - Mantenga el texto al mínimo. Los pósters son visuales — viñetas, no párrafos. Comprensión en 2 minutos.
- Empareje el estilo de referencia. Si el póster de referencia es claro/limpio, no use un tema oscuro. Empareje la estética general.
- Escalado de fuente. Todos los tamaños de texto usan
calc(Xpt * var(--font-scale))para que los botones A-/A+ funcionen. Empiece con--font-scale: 1.3y deje que el usuario ajuste. - CSS optimizado para impresión.
@media printoculta toda la interfaz de edición y establecetransform: none !important.@pageestablece dimensiones exactas. - QR de Posterskill. Incluya siempre un código QR que enlace a
https://github.com/ethanweber/posterskillen el encabezado con la etiqueta "Póster hecho con mi habilidad de Claude". - Sin pie de página de agradecimientos. Mantenga el póster limpio — sin pie de página por defecto.
- Logos en el encabezado. Descargue logos institucionales del sitio web del autor, guárdelos en
poster/logos/y enumérelos enDEFAULT_LOGOS. Se invierten automáticamente a blanco mediante filtro CSS. - Autocontenido. Sin paso de compilación, sin npm, sin servidor. Un solo archivo HTML con dependencias CDN. Funciona cuando se abre directamente como
file://. - Ecuaciones. Use KaTeX (cargado vía CDN). Escape las barras invertidas en cadenas JSX:
{'$\mathcal{E}$'}.
Manejo de figuras
- Siempre copie las figuras necesarias en
poster/— no haga referencia a rutas deoverleaf/en el HTML. - Convierta PDF a PNG en alta resolución:
sips -s format png input.pdf --out poster/output.png -Z 3000 - Descargue imágenes del sitio web mediante
page.request.get()de Playwright (no curl — los sitios web a menudo redirigen). - Mida las relaciones de aspecto con
sips -g pixelWidth -g pixelHeighty asigne a columnas según corresponda.
Flujo de trabajo del usuario para actualizaciones de configuración
El usuario puede ajustar el póster en su navegador y compartir los cambios:
- El usuario hace clic en "Copiar Config" en la barra de herramientas
- El usuario pega el JSON en el chat
- Claude actualiza
DEFAULT_LAYOUT,DEFAULT_CARD_HEIGHTS,DEFAULT_FONT_SCALE,DEFAULT_LOGOSenindex.htmlpara coincidir - Claude también escribe la configuración en
poster-config.json - El usuario actualiza y hace clic en "Restablecer" para cargar los nuevos valores predeterminados
API programática (window.posterAPI)
Disponible en la consola del navegador o mediante Playwright:
swapCards(id1, id2)— intercambia dos tarjetas (funciona entre columnas)moveCard(cardId, targetColId, position)— mueve una tarjeta a una posición específicasetColumnWidth(colId, widthMm)— establece el ancho de la columna (null para flex)- ...
[truncado para traducción]
