Boxloom: escribir presentaciones
Boxloom separa el significado de la apariencia. Solo escribes lo que el contenido es
(una lista de puntos, una comparación de opciones, un plan con fechas). La plantilla decide cada
color, tamaño de fuente, margen y posición. Nunca escribes un color, un tamaño o una coordenada
fuera de la única excepción (shapes, último recurso).
El ciclo es siempre:
boxloom schema— lee lo que las plantillas actuales aceptan (haz esto primero).- Escribe
deck.bx.md. boxloom check -format json deck.bx.md— corrige cada error, luego cada advertencia que puedas.- Repite 3 hasta que
"ok": truey no haya advertencialayout-overflow. boxloom build -o deck.pptx deck.bx.md(las banderas antes del archivo).
Los comandos se ejecutan desde el directorio boxloom/ del repositorio:
go run ./cmd/boxloom <schema|check|build|parse> … (Go 1.24+, sin otra dependencia).
1. Lee el esquema primero
boxloom schema [-template light|dark] imprime un documento JSON. Es la fuente de
verdad; si este archivo y el esquema no coinciden, el esquema gana.
markdown.rules— las reglas de sintaxis (lista corta; obedece todas).markdown.frontMatter— claves permitidas en el encabezado---(titlees obligatorio).templates[].blocks— los bloques delimitados (:::nombre) que esta plantilla conoce, coninside(dónde puede aparecer),contains(qué contiene) yminChildren.templates[].subsystems— los tipos de figuras (bloques de código```nombre), conmarkdown(sus reglas adicionales) yschema(un puntero JSON airSchemaque da todas las claves permitidas).- Cualquier cosa no listada es un error. No inventes nombres de bloques, atributos o claves.
- Las plantillas se eligen por nombre (
template: lighten el front matter, o-template dark). Una plantilla personalizada es un archivo de tabla de valores pasado por ruta:-template ./my.json(funciona paraschema,check,build,fonts; ejemploexamples/templates/forest.json). Cuando la presentación se construirá con una plantilla personalizada, ejecutaschemaycheckcon el mismo-template— los nombres de roles y estilos de texto provienen de ese archivo. variant(# Título {variant=…}) existe en la sintaxis, pero las plantillas actuales no declaran variantes (templates[].variantsestá vacío), así que no lo uses.
La salida es grande. Para ver solo lo que necesitas:
go run ./cmd/boxloom schema -template light > /tmp/schema.json
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps({'rules':d['markdown']['rules'],'blocks':d['templates'][0]['blocks'],'subsystems':[(x['name'],x['markdown']) for x in d['templates'][0]['subsystems']]},ensure_ascii=False,indent=1))"
python3 -c "import json;d=json.load(open('/tmp/schema.json'));print(json.dumps(d['irSchema']['\$defs']['gantt'],ensure_ascii=False,indent=1))" # todas las claves de gantt
2. Sintaxis en una pantalla
---
title: Trasladar el servicio de informes al nuevo clúster
subtitle: Plan y opciones (ejemplo ficticio)
author: Equipo de plataforma
date: 2026-11-11
confidential: Interno
disclaimer: Todos los nombres y cifras son ficticios
template: light
---
# Soporte del proveedor para el clúster antiguo
:::lead
El clúster antiguo pierde el soporte del proveedor en marzo de 2028, por lo que los 14 servicios que contiene deben migrar antes de esa fecha.
:::
- El soporte del proveedor finaliza las correcciones de seguridad el **2028-03-31**
- 14 servicios aún se ejecutan allí; 9 pueden migrar sin cambios de código
- La migración lleva unas 6 semanas por grupo de servicios
:::source
Aviso de soporte del proveedor de 2026-09; inventario de servicios a octubre de 2026
:::
:::notes
Las notas del orador van aquí. Solo párrafos y viñetas.
:::
-
# Títuloinicia una diapositiva. Mantén el título como un encabezado breve que quepa en una línea ("Soporte del proveedor para el clúster antiguo"); un título que se envuelve se advierte (title-wrap). Escribe lo que dice la diapositiva — la conclusión — como una oración en:::leadjusto después del título (1–2 líneas). La plantilla coloca el lead debajo del título, fuera del cuerpo. -
---no es un separador de diapositivas (es un error).##y encabezados más profundos son errores (un título de grupo se escribe como:::columna Título, no como un subencabezado). -
Cuerpo: párrafos, viñetas
-/1.(máximo dos niveles),**énfasis**(solo un tipo de énfasis),`código`,[texto](url),\al final para un salto de línea significativo. Sin cursivas, tachado, notas al pie, HTML. -
Bloques delimitados: abre con
:::nombrey cierra con la misma cantidad de dos puntos. Al anidar, el bloque exterior obtiene un punto más que el interior::::::comparar ::::opción Mantener el clúster antiguo :::pros - Sin trabajo de migración este año ::: :::cons - Sin correcciones de seguridad después de marzo de 2028 ::: :::: ::::opción Migrar al nuevo clúster :::pros - Con soporte hasta 2033 ::: :::cons - Seis semanas de trabajo por grupo de servicios ::: :::: ::::: -
:::lead(el mensaje de la diapositiva),:::notes(notas del orador) y:::source(de dónde provienen los números de la diapositiva) deben estar en el nivel superior de una diapositiva, una vez por diapositiva cada uno.:::leades solo para diapositivas de contenido. -
date,confidentialydisclaimeren el front matter se escriben una vez para toda la presentación; la plantilla los coloca en la portada (yconfidentialen el pie de página). Nunca repitas "ficticio" / "confidencial" en una:::noteen cada diapositiva. -
Las figuras son bloques de código delimitados cuyo lenguaje es el nombre del subsistema, el cuerpo en YAML restringido: sin anclas/alias (
&,*), sin etiquetas, sin valores multilínea, sin bloques|/>; booleanos solotrue/false; las fechas son cadenasYYYY-MMoYYYY-MM-DD; rangos2027-01 .. 2027-06. Pon entre comillas cualquier valor que comience con*,&,!o que contenga": ", por ejemplo,text: ["**Paso más lento**", 5 días en promedio]— un**…**sin comillas al inicio de un elemento de flujo se interpreta como un alias de YAML y se rechaza.
3. Elegir un patrón para cada contenido
Decide el tipo de contenido antes de escribir. Aplica estas reglas en orden y usa la
primera que coincida. (Conjunto completo de reglas con ejemplos buenos/malos: docs/patterns.md §4.)
Disponibles ahora (consulta boxloom schema — pueden haberse añadido más):
| Contenido | Usar | Notas |
|---|---|---|
| Un corte de capítulo | # Parte 2: Cómo migramos {type=section} | El texto del encabezado es el título del capítulo; nada más que :::notes puede seguir. No es una tabla de contenido — cuando la presentación tiene dos o más secciones, la plantilla dibuja la lista de capítulos con el actual resaltado en cada diapositiva de sección por sí misma |
| La diapositiva dice exactamente una oración; la evidencia está en otras diapositivas | # La migración debe adelantarse dos años {type=statement} | El texto del encabezado es la oración (este es el único tipo de diapositiva cuyo encabezado es una oración completa); nada más que :::notes y :::source puede seguir. Si agregarías razones, usa una diapositiva normal con un título corto y la conclusión como :::lead |
| 1–4 números para mostrar con fuerza, sin series para comparar | ::::stat → :::value 3 → 12 {unit=modelos} + etiqueta de una línea dentro | 5+ números o una serie temporal es un gráfico/tabla, no stat. El valor se escribe tal cual y debe contener un dígito. El valor y la unidad nunca se rompen en el medio, así que mantenlos cortos — 4 tarjetas son estrechas (stat-value) |
| Una serie de números (3+ puntos): ranking, cambio en el tiempo, parte de un total, distribución, relación de dos cantidades | ```chart | compare: item / timeSeries / component / frequency / correlation — el tipo de gráfico se elige por ti (nunca escribas barra/línea/pastel). categories: [...], series: [{name, values: [...]}] (un valor por categoría, números sin comillas, máximo 3 series), opcional unit, emphasis: [category] (una serie) o emphasis: true en una serie, stacked: true cuando las series son partes de un total. correlation usa xAxis: {title, unit?}, yAxis y points: [[x, y], …] en lugar de categorías. component (parte) tiene 1 serie y ≤ 6 partes — fusiona partes pequeñas en "Otros" |
| Palabras de otra persona | :::quote Texto fuente + las palabras dentro | La fuente (texto del encabezado) es obligatoria. Nunca cites tu propia conclusión |
| Una oración para enfatizar dentro de una diapositiva normal | :::takeaway + una oración | Como máximo una por diapositiva, generalmente al final |
| Filas × columnas de texto simple o números | Tabla GFM: | A | B | + | --- | --- | + filas | La primera fila es el encabezado; cada fila tiene una celda por columna (table-shape). Sin marcadores de alineación (:--, --: son errores); las columnas numéricas se alinean a la derecha por ti. Las celdas son solo en línea. Una línea : leyenda justo después de la tabla es su leyenda. Si la última fila es un total, termina esa línea con {total=last} (: Estimaciones {total=last}, o solo : {total=last}); se dibuja como fila de total. Los totales no se calculan — escribe el valor. Pon la unidad una vez en la leyenda o el encabezado, no en cada celda. Calificaciones en celdas → matrix (abajo) |
| Filas × columnas donde cada celda es una calificación (compatible / condicional / no / riesgo) | ```matrix | columns: [A, B], rows: [{label, cells: [{status, text?}]}], opcional legend: {support: Bueno}. Una celda por columna (matrix-cells). La opción recomendada: emphasis: <texto del encabezado de columna> (exactamente como está escrito en columns, matrix-emphasis) — nunca digas "la columna azul" en prosa. Las celdas que son texto simple o números son una tabla, no una matriz |
| 3–7 pasos sin fechas, en una dirección (la salida de uno es la entrada del siguiente) | ```process | steps: [{title, detail?, status?, emphasis?}], opcional caption. Los números (1. 2. …) y las flechas se añaden por ti; los procesos largos se envuelven a una segunda fila. Si usas status, di lo que significa en legend: {conditional: Necesita aprobación} (figure-legend) |
| Dos o más opciones, cada una con pros y contras | :::compare → :::option → :::pros / :::cons | Si 3+ criterios compartidos se aplican a cada opción, una matriz encaja mejor (arriba) |
| Un padre con hijos (y nietos): configuración de equipo, propiedad | ```orgchart | root: {title, detail?}, units: [{title, detail?, members: [{title, detail?}]}]. 3 niveles máximo. Un status en una caja necesita legend: {conditional: Se necesitan dos personas más} — la leyenda debajo del gráfico lo explica; no expliques los colores del contorno en una :::note. No para equipos no relacionados uno al lado del otro |
| Etapas cuyo recuento se reduce (visitas → registros → pagos) | ```funnel | stages: [{label, value, note?}], opcional unit. value es un número o texto; los anchos de las barras son escalonados, no proporcionales. Las tasas de conversión etapa a etapa (↓ 45%) se dibujan por ti a partir de valores numéricos — no las escribas en note; usa note para explicar por qué una etapa disminuye. status necesita legend. Los valores que crecen se advierten (funnel-increase) — usa process para pasos simples |
| Un plan con fechas, períodos, plazos, estados a lo largo del tiempo | ```gantt | Los estados son support, conditional, none, danger (roles, no colores). Los períodos de hardware/riesgo de soporte son un grupo risk: A .. B. Las anotaciones apuntan a un id de grupo/fila mediante target; el subsistema las coloca |
| 2–3 grupos paralelos leídos uno al lado del otro ("este año / el próximo año / no se hace") | ::::columns → :::column Título del grupo (2 o 3) | Cada grupo contiene párrafos, viñetas, una tabla, una imagen, un ```chart o :::note. Sin columnas anidadas, comparaciones, galerías u otras figuras. Gráfico + su lectura uno al lado del otro: gráfico en un grupo, las conclusiones como viñetas en el otro. Los anchos no son números: marca el grupo principal {role=main} (los otros lo apoyan) o déjalos iguales. 4+ grupos de una línea → viñetas. No para un argumento dividido en dos |
| Una imagen que muestra el punto (captura de pantalla, foto, dibujo) | un párrafo que contiene solo  | El texto alternativo es obligatorio (image-alt). La ruta es relativa al archivo de la presentación; sin URLs, rutas absolutas o .. (image-path). Solo PNG o JPEG (image-format). Se mantiene en proporción, nunca recortada. Imagen + texto uno al lado del otro → ::::columns con la imagen en un grupo |
| 2–6 imágenes comparadas o en secuencia | un párrafo con 2–6  | Se convierte en una galería (una fila para 2–3, una cuadrícula para 4–6). 7+ es un error: divide la diapositiva |
| Puntos paralelos | viñetas | 2 niveles máximo |
| Prosa conectada | párrafo | 2–3 oraciones |
| Lo que dice la diapositiva: su conclusión en una o dos oraciones | :::lead en el nivel superior de una diapositiva de contenido, un párrafo | Cada diapositiva de contenido tiene uno. Colocado por la plantilla justo debajo del título, fuera del cuerpo; toma espacio del cuerpo (1 línea ≈ 32 pt, 2 líneas ≈ 57 pt). Cuando necesita dos líneas, el motor lo rompe después del final de una oración (。) o, si no, después de una coma (、) sin agregar una línea — por lo que dos oraciones cortas se leen mejor. No es un resumen de las viñetas — es la afirmación que demuestran |
| De dónde provienen los números, tabla, figura o cita de la diapositiva (fuente, tamaño de muestra, fecha) | :::source en el nivel superior de la diapositiva, un párrafo | Toda diapositiva que muestra números, una tabla, un gráfico o una cita tiene uno. Solo diapositivas de contenido y declaración (no de sección). Colocado por la plantilla debajo del cuerpo, encima del pie de página; toma espacio del cuerpo (layout-overflow lo cuenta). Una por diapositiva: varias fuentes van en un párrafo |
| Fecha, confidencialidad, descargo de responsabilidad para toda la presentación ("todas las cifras son ficticias") | front matter date, confidential, disclaimer | Escrito una vez; se muestra en la portada (y confidential en el pie de página) |
| Una advertencia / comentario similar a una nota al pie | :::note | Una línea corta. No para fuentes (:::source), no para el descargo de responsabilidad de toda la presentación (front matter), y nunca para la conclusión o un número clave |
| Un diagrama cuyas posiciones/conexiones tienen significado y ninguno de los anteriores encaja | ```shapes | Último recurso, ver §3.1 |
En las cuatro figuras anteriores solo escribes texto, status (support, conditional,
none, danger) y emphasis: true; la posición, el tamaño y el color provienen de la plantilla.
En chart solo escribes lo que se compara y los números; el gráfico es un gráfico real de
PowerPoint cuyos valores permanecen editables. Enfatiza el único punto que el título expresa:
compare: timeSeries
unit: " registros"
categories: [Abr, May, Jun, Jul, Ago, Sep]
emphasis: [Sep]
series:
- name: Registros
values: [120, 150, 1
…
[truncado para la traducción]
