Communitygithub.com

swiss-pdf

Convierte archivos md / docx / txt / html en PDFs A4 con estilo de diseño suizo internacional. Fondo blanco, texto negro, líneas divisorias ultrafinas, números de sección grandes, números monoespaciados, tira de color en la portada, tabla de contenidos automática, encabezados y pies de página. Soporta siete tipos de bloques de estilo: note/quote/inverse/warn/stat/check/kv.

¿Qué es swiss-pdf?

swiss-pdf es una habilidad para agentes de IA (como Claude Code, Cursor, Codex) que transforma documentos Markdown, DOCX, TXT y HTML en PDFs A4 con un estilo de diseño suizo internacional, profesional y minimalista. Está diseñada para desarrolladores y usuarios que necesitan producir documentos formales y limpios de manera rápida, sin necesidad de herramientas de diseño complejas. La habilidad convierte automáticamente el contenido, aplica una plantilla CSS con tipografía, colores, espaciado y reglas de paginación precisas, y utiliza un navegador Chromium (via Playwright) para renderizar el PDF final. Soporta características como portada YAML, tabla de contenidos automática, siete tipos de bloques de estilo (notas, citas, advertencias, etc.) y manejo inteligente de tablas, imágenes y encabezados. Es ideal para generar reportes, documentación técnica, propuestas y cualquier otro documento que requiera una presentación impecable.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/echoBai83/swiss-pdf/tree/HEAD

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace swiss-pdf?

Convierte archivos md / docx / txt / html en un PDF A4 con estilo de diseño suizo internacional. Fondo blanco, texto negro, líneas divisorias ultrafinas, números de sección grandes, números monoespaciados, y un único color rojo #E5484D para énfasis.

Los tokens de diseño provienen de un libro de estilo suizo (números de sección grandes, líneas divisorias ultrafinas, un solo color de acento), adaptado a un flujo de paginación automática, por lo que funciona con documentos de cualquier longitud directamente.

Cómo usar

Método 1: Arrastrar y soltar (recomendado)

Arrastra el archivo a swiss-pdf.bat → se genera un PDF con el mismo nombre en el mismo directorio, junto con una copia xxx.pdf-src.html (fuente HTML para revisión).

Método 2: Línea de comandos

python make.py archivo_entrada                    # Genera PDF
python make.py archivo_entrada --html             # Solo genera HTML (se guarda como xxx.html, se puede abrir en el navegador e imprimir manualmente)
python make.py archivo_entrada -o salida.pdf
python make.py a.md b.docx c.txt                  # Procesamiento por lotes
python make.py archivo_entrada --no-cover --no-toc
python make.py archivo_entrada --title "Título" --kick "Nota al margen" --date 2026.11.09

Formatos de entrada soportados

FormatoMétodo de conversiónDescripción
.mdpandocSoporta YAML front-matter, tablas GFM, listas, bloques de código, imágenes
.docxpandocEstilos de título → títulos de sección; tablas → tabla con estilos; imágenes extraídas automáticamente
.txtAnalizador internoPárrafos separados por líneas en blanco; líneas cortas numeradas (一、/ 1. / 第X章) → títulos de sección
.htmlAnalizador internoToma <body>, elimina script/style; <title> como título del documento

Portada: YAML front-matter

Escrito al principio del archivo md (otros formatos usan parámetros como --title):

---
title: Libro Blanco de Seguridad en Ciclismo Urbano
subtitle: Observaciones y recomendaciones basadas en una encuesta en tres ciudades
kick: Investigación en Gestión del Tráfico
en: Urban Cycling Safety White Paper
slug: seguridad-ciclismo-urbano
nature: Versión Pública
project: Programa de Estudio de Sistemas de Movilidad Lenta
party_a: Nombre del Cliente
party_b: Nombre del Proveedor
stage: Investigación → Redacción → Aprobación
source: 01_Registros de observación 02_Resúmenes de entrevistas 03_Plan
date: 2026.11.10
version: v2.1
badges: Público; !Importante; Con Datos
---
  • badges se separa con ;, los prefijados con ! son fondo negro con texto blanco.
  • Si no se completa date, se usa la fecha actual automáticamente.
  • Funciona sin front-matter; la portada solo muestra el título + fecha + espacio para versión.

Cuerpo del texto: Siete tipos de bloques de estilo

En markdown, se envuelven con ::: (cada línea dentro del bloque = un elemento):

::: note
Nota complementaria, aclaración de alcance. Fondo gris.
:::

::: quote
Cita de conclusión clave, con línea vertical izquierda de 3pt.
:::

::: inverse
Bloque de fondo negro con texto blanco, para la frase más importante.
:::

::: warn
Advertencia con borde rojo, único lugar donde se permite color.
:::

::: stat
4,280 | Total de muestras observadas || 24 | Puntos de observación || 3 | Ciudades cubiertas
:::

::: check
Intersección de hora punta matutina (llegar antes de las 7:30)
Tramos de carretera iluminados por la noche (necesitan luz de relleno)
:::

::: kv
Páginas | Plan A 20 páginas / Plan C 32 páginas
Recomendación | Plan C, pero necesita completar datos de la segunda ciudad
:::

stat usa número | descripción por celda, || separa celdas. kv usa clave | valor.

Comportamiento automático

ComportamientoRegla
Numeración de secciones# Título de nivel 1 → número grande 00/01/02…; si el título ya incluye numeración como «01 » o «一、», se mantiene
Tabla de contenidosSolo se genera si hay al menos 5 elementos entre secciones (#) y subsecciones (##); de lo contrario se omite la página; los títulos de sección tienen anclajes enlaces dentro del PDF
TablasSi el número de columnas es ≥ 6, se reduce el tamaño de la fuente (table.wide); las celdas con solo números se alinean a la derecha y usan fuente monoespaciada
Encabezado y pie de páginaLa portada no tiene encabezado/pié; en el cuerpo, el encabezado izquierdo muestra el título del documento, y el pie derecho muestra «Página i / Total N»
Impresión@page A4, márgenes 14/15/13mm; los títulos no se separan del texto del párrafo, las filas de las tablas no se rompen entre páginas

Procesamiento adicional de fuentes HTML (complementos verificados)

Cuando la fuente es una «página web con diseño propio», esta habilidad aplica automáticamente las siguientes normalizaciones para evitar números sueltos o títulos duplicados después de reordenar:

Estructura de fuenteProcesamiento
<div class="sec-head"><span class="sec-num">3</span><h2>Título</h2></div>Se convierte en el encabezado de sección .sec de la plantilla (el número se toma de span, el título de h2)
<h1>03 Título</h1> / <h1>Título</h1>Igual que arriba; si no hay número, se autoincrementa según el orden de aparición
Párrafo de solo números <p>0</p>Se descarta (común en diseños donde el número de sección se usa como decoración)
<header class="masthead"> / <nav>Se descarta (la portada ya se genera por separado; los kickers/títulos grandes/tablas de contenido duplicados contaminarían el cuerpo)
Secciones <section>Se mantienen como contenedores de sección; el título aún necesita sec-head o h1 para aparecer en la tabla de contenidos
<div id="xxx" class="chart"> + echartsSe captura la pantalla del gráfico con un navegador sin cabeza y se incrusta como PNG; antes de la captura se espera networkidle + 2.5s

Requisito previo para la captura de gráficos: si echarts se carga desde una CDN, se necesita conexión a internet; en entornos sin conexión, incrusta echarts.min.js directamente en la fuente.

Fuentes y puntuación

Fuentes: El repositorio incluye Source Han Sans, incrustado con @font-face

La carpeta fonts/ del repositorio contiene dos archivos; make.py los incrusta como base64 en el <style> al generar el HTML, registrándolos como la familia de fuentes Swiss Sans SC:

ArchivoPeso
SourceHanSansCN-Regular.subset.ttf400
SourceHanSansCN-Bold.subset.ttf700

El subconjunto abarca aproximadamente 7100 caracteres (ASCII + signos de puntuación chinos e ingleses + todos los 6763 caracteres chinos de GB2312). El conjunto de caracteres se encuentra en fonts/charset.txt. Ventaja: En una máquina que no tenga Source Han Sans instalada, la salida es completamente consistente; el usuario no necesita instalar la fuente.

El usuario puede reemplazar o descargar la fuente, tres opciones (consulta fonts/README.md):

  1. Reemplazar archivos (recomendado): Renombra tu propio TTF con los nombres de los archivos anteriores y sobrescríbelos. Primero, crea un subconjunto, de lo contrario el HTML se llevará el archivo completo de 10 MB:
    pyftsubset tu-fuente-Regular.ttf --text-file=fonts/charset.txt --output-file=fonts/SourceHanSansCN-Regular.subset.ttf
    
  2. Eliminar la carpeta fonts/: Si make.py no detecta los archivos, omite @font-face y recurre a la pila de fuentes del sistema en CSS (Source Han Sans SC/CN → Noto Sans SC → Noto Sans CJK SC → 梦源黑体 CN → PingFang SC → Segoe UI Symbol).
  3. Solo modificar CSS: Cambia el primer nombre de fuente en --sans al principio de templates/swiss.css.

⚠️ Debe ser .ttf (contornos TrueType), no .otf (CFF). Chromium, al imprimir PDF, degrada las fuentes web CFF a instrucciones de glifo Type3 (cada glifo almacena una ruta de dibujo), multiplicando el tamaño. El mismo documento de 4 páginas: OTF → 328 KB / 205 Type3; TTF → 79 KB / 1 Type3.

Microsoft YaHei en Chromium carece de glifos para · (U+00B7), → ↓ ≤ ≥ y otros símbolos, que se muestran como cuadrados, por lo que se ha eliminado de la pila de fuentes principal.

Comillas: Se fuerza el uso de comillas curvas estándar nacionales en todo el texto

convert.normalize_quotes() se encarga de esto en el último paso de la conversión, cubriendo títulos, portada, encabezados, tabla de contenidos, tablas y bloques de estilo:

EntradaSalida
「」“”
『』‘’
Comillas rectas " ' en códigoMarkdown pasa por pandoc +smart y las convierte automáticamente a comillas curvas; dentro de los bloques de código <code> / <pre> no se modifican

La implementación solo reemplaza 4 puntos de código (U+300C/D/E/F → U+201C/D/8/9), sin tocar atributos de etiquetas HTML ni CSS/JS.

Registros de ejecución verificados

EntradaTamañoPáginasTiempo
md29 KB15~6s
html105 KB + 2 gráficos echarts21~15s
docxEstilos de título + tabla2~6s
txt (samples/)1.2 KB2~5s
md documento largo (regresión)71 KB21~24s

Dependencias del entorno

DependenciaEstado actualSi falta
pandoc (≥2.19)Ejecuta pandoc -v para confirmarNo se pueden convertir md/docx
playwright + chromiumO Chrome / Edge del sistemaNo se puede renderizar PDF
python-docx (opcional)Solo para análisis auxiliarNo afecta el flujo principal

Para especificar un navegador: set SWISS_PDF_CHROME=<ruta a chrome.exe>

Estructura del proyecto

swiss-pdf/
├── SKILL.md              Este archivo
├── swiss-pdf.bat         Acceso por arrastrar y soltar
├── make.py               Flujo principal: convertir → ensamblar → renderizar
├── convert.py            Convertir cada formato → fragmento HTML + sintaxis de bloques
├── templates/
│   └── swiss.css         Todos los estilos (tokens de diseño + reglas de impresión)
└── samples/              Ejemplos de muestra en tres formatos

Límites (lo que no puede hacer)

  • Paginación manual como en un libro de lujo (colocación cuidadosa del contenido en cada página, diseño a doble página) la plantilla no lo puede hacer; aún se necesita escribir HTML a mano. El objetivo de esta habilidad es «redactar documentos comunes rápidamente».
  • Maquetación de ilustraciones: depende del tamaño de las imágenes en el documento original; no se realizan recortes ni sangrados.
  • Numeración de páginas de la tabla de contenidos a la derecha: no implementado (los elementos dentro de la página no pueden obtener el número de página); los títulos de sección tienen enlaces que se pueden hacer clic, y el pie de página muestra «Página i / Total N».
  • Los bloques de tabla demasiado cortos pueden moverse a la página siguiente: para evitar que las tablas de valor clave se dividan, el bloque .kv no se puede dividir entre páginas.
  • Estilos complejos de Word (cuadros de texto, WordArt, listas con numeración multinivel) se degradarán al ser convertidos por pandoc.

Skills relacionados