Saltar al contenido principal

Capítulo 3.14 · Parte II · El oficio

Configuración: páginas compuestas

Plantillas de página para las páginas compuestas: marcos, grupos, decoración, herencia y variantes de recto y verso, los estilos de rótulo de los anclajes de una imagen y los avisos que puede dar una plantilla

Actualizado 2026-10-166 minEn el capítulo 3 Configuraciónenescadefritptzhjaar

En pocas palabras

Esta página trata de las plantillas de página. Una plantilla es una página dibujada en los ajustes: unas cajas con nombre, llamadas marcos, con su sitio, el tamaño hasta el que pueden crecer y su aspecto. El Markdown de una página compuesta llena después esos marcos por su nombre, así que el texto nunca guarda posiciones y los ajustes nunca guardan texto. Una plantilla puede partir de otra y cambiar solo unos pocos marcos, y puede ser distinta en las páginas pares y en las impares. La página recoge también los estilos de rótulo para las palabras que se ponen sobre una imagen, y cada aviso que puede dar una plantilla con la manera de corregirlo.

#Plantillas de página

Una página compuesta es una página que toma su forma de una plantilla de página de la configuración y su contenido del Markdown de un bloque ::::page{template="…"}. La plantilla da nombre a unos rectángulos, llamados marcos; el Markdown manda cada pieza de contenido a un marco por su nombre (su hueco). La geometría nunca aparece en el Markdown, y el texto del contenido nunca aparece en la plantilla. La propiedad pageTemplates guarda las plantillas del libro:

const config: PostextConfig = {
  calloutStyles: [{ id: 'caja-azul' }, { id: 'tab-titulo' }],
  pageTemplates: [
    {
      id: 'tema-cajas',
      decoration: {
        elements: [
          { kind: 'image', id: 'fondo', resourceId: '{attr.fondo}', decorative: true,
            placement: { anchor: { to: 'bleed', edge: 'top-left' }, size: { width: 'fill', height: 'fill' } } },
        ],
      },
      frames: [
        { name: 'titulo', takes: 'h1', style: 'tab-titulo' },
        { name: 'texto', flow: true },
        { name: 'dinero', style: 'caja-azul', padding: { right: { value: 62, unit: 'mm' } } },
        { name: 'dinero-fotos', layer: 2, width: { value: 60, unit: 'mm' },
          placement: { anchor: { to: '#dinero', edge: 'top-right' } } },
      ],
      groups: [
        { name: 'pagina', kind: 'stack', gap: { value: 6, unit: 'mm' }, frames: ['titulo', 'texto', 'dinero'] },
      ],
    },
  ],
};

Una plantilla que solo fija su id y un marco es una página entera con ese marco ocupando el área de texto. Todos los demás campos son opcionales:

PropiedadTipoPor defectoDescripción
idstringobligatorioEl nombre que pide un bloque de página (template="tema-cajas"). Único entre las plantillas: una segunda con el mismo id se ignora.
namestringel idEl nombre que muestra el Sandbox. La composición nunca lo lee.
extendsstringningunoEl id de la plantilla de la que parte esta. Ver Herencia y variantes.
area'content' | 'trim' | 'bleed''content'El rectángulo al que se refieren las posiciones de los marcos. 'content' es el área de texto de la página, reflejada en pares e impares como el texto corrido; 'trim' es la página al corte; 'bleed', la página con su sangrado.
grid{ columns, rows, columnGap?, rowGap? }ningunaDivide el área en celdas, de modo que un marco o un grupo se puede colocar por celda (grid: { col: 2, row: 1, cols: 2 }, contando desde 1) en lugar de por placement. Los espacios valen 0 por defecto.
framesFrameConfig[][]Los marcos, en el orden de la plantilla: el orden en que se miden y el que deshace los empates. Ver Marcos.
groupsFrameGroupConfig[][]Pilas y filas de marcos que se reparten el espacio. Ver Grupos.
decorationDesignSlotningunaImágenes, filetes y cajas que se pintan con la página, en el lenguaje de elementos de los encabezados y pies. Los elementos de texto solo llevan marcadores ({pageNumber}, {chapterTitle}, {attr.x} para un atributo del bloque de página). Un elemento se puede anclar a un marco o a un grupo ('#dinero') y entonces se mueve con él. La decoración se coloca después de los marcos y nunca empuja el texto.
header, footerDesignSlot | falseheredadosLa cabecera y el folio de la página. Sin fijar, la página conserva los de su capítulo; false los oculta.
spreadbooleanfalseLa plantilla describe dos páginas enfrentadas compuestas como un solo pliego. Una doble página empieza siempre en una página par en un libro de izquierda a derecha (en una impar en uno de derecha a izquierda), con una página en blanco delante cuando hace falta.
gutterDimension0En una doble página, la franja junto al lomo que los marcos dejan libre, salvo que fijen crossGutter: true.
variants{ recto?, verso? }ningunaCambios para una página impar (recto) o una par (verso), escritos como la propia plantilla. El lado es el físico, así que funcionan tanto los libros de izquierda a derecha como los de derecha a izquierda.
overflowTemplatestringesta plantillaLa plantilla de las páginas que se añaden cuando un marco continúa en la página siguiente (overflow.continueIn: 'next-page'). Sin fijar, la página añadida usa esta plantilla con solo los marcos que continúan llenos.
bodyStylestringningunoUn estilo de párrafo para el texto de la página, como el que tienen los estilos de encabezado.
palettestringningunaUna paleta propia para la página, como la que tienen los estilos de encabezado y las partes.
rolestring'composed'El papel de página que ven los elementos de diseño con un filtro pages.

#Marcos

Un marco es un rectángulo con nombre que recibe contenido compuesto. Su name es el hueco que pide el Markdown, y es único en su plantilla (un grupo tampoco puede llevar el nombre de un marco, porque los anclajes nombran a los dos de la misma manera).

Un marco se coloca por su celda de grid cuando la plantilla tiene rejilla y, si no, por su placement, que funciona como el de un elemento de diseño: un anclaje ('container' es el área, 'page', 'bleed', o '#name' para otro marco o grupo), un borde, un desplazamiento y un tamaño. Un marco anclado a otro se mueve con él. Sin ninguno de los dos, el marco ocupa toda el área.

PropiedadTipoPor defectoDescripción
namestringobligatorioEl nombre del hueco.
placementElementPlacementtoda el áreaAnclaje, borde, desplazamiento y tamaño, como en el posicionamiento de elementos. Se ignora cuando una celda de la rejilla coloca el marco.
grid{ col, row, cols?, rows? }ningunaUna celda de la rejilla de la plantilla, contando desde 1, que abarca cols × rows celdas (1 por defecto). Una celda que se sale de la rejilla vuelve a meterse en ella. Se ignora cuando la plantilla no tiene rejilla.
width, heightDimension | { percent } | 'auto' | 'fill''fill', 'auto'Una longitud fija, un porcentaje del área (de 0 a 100), 'auto' (el tamaño propio del contenido) o 'fill' (lo que queda hasta el borde al que está anclado el marco). Sin fijar, el marco lee placement.size y después el valor por defecto: todo el ancho y tan alto como su contenido. Un marco de texto necesita una medida, así que un ancho 'auto' solo tiene sentido en un marco que lleva una sola imagen (el ancho de la imagen a la altura del marco). Un valor que el motor no puede usar (una longitud negativa, una unidad desconocida) se lee como el valor por defecto.
minWidth, maxWidth, minHeight, maxHeightDimensionningunoLímites para un tamaño 'auto' o 'fill' y para el espacio que un grupo da o quita. El mínimo se impone al máximo, y un tamaño fijo fuera de ellos se lleva dentro (frameMinMax avisa de los dos casos).
stylestringsin cajaEl id de un estilo de aviso: los marcos se dibujan con estilos de aviso (fondo, borde, relleno, banda, icono, pestaña de rótulo, título). Las palabras de una pestaña vienen del Markdown (:::frame{slot="dinero" label="El dinero"}). Los ajustes de aviso que dicen dónde va una caja en el texto corrido (placement, span, columns, width, fixed…) no se aplican a un marco.
padding{ top?, right?, bottom?, left? }el del estiloSustituye el relleno del estilo lado por lado: sitio para las fotos que van encima de una caja, por ejemplo.
layernumber1Orden de pintado. La decoración es la capa 0; una capa negativa se pinta debajo de ella.
rotatenumber0Grados, en el sentido de las agujas del reloj. La caja y su contenido giran juntos.
verticalAlign'top' | 'middle' | 'bottom' | 'justify''top'Dónde se sitúa el contenido en un marco más alto que él.
columns, columnGapnumber, Dimension1, el del estiloColumnas dentro del marco.
exclude'none' | 'push''none''push': el texto de los demás marcos rodea el rectángulo de este.
flowbooleanfalseEl marco recibe el contenido que no nombra ningún hueco.
takes'h1' … 'h6'ningunoEl marco recibe el primer encabezado de ese nivel que no nombra ningún hueco, así que el título de una página es solo un # Título al principio del bloque.
nextstringningunoUna cadena: el contenido que no cabe sigue en el marco de ese nombre, en la misma página.
overflow.continueInstringningunoDónde sigue el contenido que no cabe: '#frame' (otro marco de la página, como next), 'next-page' (el mismo marco en una página que se añade detrás de esta) o 'template:<id>' (una página de esa plantilla).
overflow.markstring | falsela del idiomaLa marca al final de un trozo cortado. Sin fijar, la palabra de continuación del idioma del documento (la misma que usan las tablas partidas); false no pone ninguna.
fit.shrinkTextbooleantrueCuando nada más consigue que el contenido quepa, su texto se puede componer más pequeño.
fit.minScalenumber0.9La escala de texto más pequeña, mayor que 0 y como mucho 1 (un valor mayor se lee como 1).
fit.scaleImages, fit.imageMinScaleboolean, numbertrue, 0.8Si las imágenes del marco se pueden componer más pequeñas, y hasta qué escala.
pinbooleanfalseEl marco nunca se mueve ni cambia de tamaño, para una caja que debe quedar alineada con la ilustración. Un grupo se coloca alrededor de él.
grow, shrink, prioritynumber0Cómo comparte el marco el espacio de su grupo: grow toma una parte del espacio sobrante, shrink deja que el marco devuelva espacio, y los marcos con una priority más baja lo ceden primero.
optionalbooleanfalseNingún aviso cuando el Markdown no manda nada al marco.
crossGutterbooleanfalseEn una doble página, el marco puede cruzar la franja del lomo.
writingMode, direction'horizontal-tb' | 'vertical-rl', 'ltr' | 'rtl'los de la páginaUna caja vertical en una página horizontal, o al revés.
removebooleanfalseEn una plantilla que extiende otra, o en una variante: quita el marco heredado con ese nombre.

#Grupos

Un grupo es una pila (de arriba abajo) o una fila (del principio al final) de marcos que se reparten el espacio y se mueven juntos. Dentro de un grupo se ignora la posición propia de los marcos en la dirección del grupo: el grupo los coloca en orden, con gap entre ellos. Cuando crece el texto de un marco, los marcos que van detrás se desplazan. Un grupo es una caja a la que pueden anclarse marcos y decoración ('#pagina').

PropiedadTipoPor defectoDescripción
namestringobligatorioÚnico entre los marcos y grupos de la plantilla.
kind'stack' | 'row''stack'De arriba abajo, o del principio al final.
framesstring[][]Los marcos del grupo, en su orden en la página. Un marco pertenece como mucho a un grupo; un nombre que no es ningún marco de la plantilla, o un marco ya listado, se salta.
gapDimension0El espacio entre dos marcos del grupo.
placement, gridcomo en los marcosla caja de sus marcosLa caja propia del grupo. Sin fijar, la caja que rodea las cajas declaradas de sus marcos.
align'start' | 'center' | 'end' | 'space-between''start'Adónde va el espacio sobrante cuando ningún marco del grupo crece.
removebooleanfalseEn una plantilla que extiende otra, o en una variante: quita el grupo heredado.

#Herencia y variantes

Una plantilla con extends parte de la plantilla que nombra (que a su vez puede extender otra) y cambia solo lo que escribe:

  • Un campo como area, header u overflowTemplate sustituye al del padre. grid se combina clave a clave. spread, gutter y role también se heredan; id, name y extends son propios de la plantilla.
  • frames y groups se combinan por nombre: una entrada con el nombre de una heredada cambia los campos que escribe y conserva el resto (fit, overflow y padding se combinan clave a clave; placement se sustituye entero); remove: true la quita; un nombre nuevo se añade detrás de los heredados.
  • Los elementos de decoración se combinan por id de la misma manera; un elemento con un id nuevo, o sin id, se añade.

variants.recto y variants.verso se escriben como una plantilla y se combinan igual, en una página impar o en una par. Se aplican después de toda la cadena de extends, primero la variante de la raíz. Una doble página tiene los dos lados, así que no se le aplica ninguna variante.

pageTemplates: [
  { id: 'tema', frames: [{ name: 'texto', flow: true }, { name: 'margen', width: { value: 30, unit: 'mm' },
      placement: { anchor: { to: 'container', edge: 'top-left' } } }],
    variants: { recto: { frames: [{ name: 'margen', placement: { anchor: { to: 'container', edge: 'top-right' } } }] } } },
  { id: 'tema-sin-margen', extends: 'tema', frames: [{ name: 'margen', remove: true }] },
]

Cuando el Sandbox guarda una plantilla, nunca descarta un valor igual al valor por defecto: en una plantilla que extiende otra, o en una variante, ese valor sustituye al del padre.

Desde código, resolvePageTemplate(config, id, { parity }) devuelve una plantilla con su cadena combinada, la variante del lado aplicada, todos los valores por defecto rellenos y cada referencia resuelta como describen los avisos de abajo; validatePageTemplates(config) devuelve los avisos.

#Estilos de rótulo

La propiedad labelStyles da nombre a los aspectos de los rótulos que se ponen sobre una imagen: los mares y las ciudades de un mapa, las partes de un esquema. Un rótulo se sitúa en un anclaje de la imagen (un punto guardado con el recurso, como los hablantes de un cómic) y toma el estilo que nombra el anclaje o el rótulo.

labelStyles: [
  { id: 'mar', fontStyle: 'italic', textTransform: 'uppercase', letterSpacing: 0.12,
    color: { hex: '#2b6ca3', model: 'hex' } },
  { id: 'ciudad', fontWeight: 600, halo: { color: { hex: '#ffffff', model: 'hex' }, width: { value: 0.6, unit: 'pt' } } },
]
PropiedadTipoPor defectoDescripción
idstringobligatorioEl nombre que usan los anclajes y los rótulos.
namestringel idEl nombre que muestra el Sandbox.
paragraphStylestringningunoUn estilo de párrafo del que el rótulo toma la letra; los campos de abajo lo sustituyen.
fontFamily, fontSize, fontWeightstring, Dimension, numberlos del texto generalLa letra del rótulo.
fontStyle'normal' | 'italic''normal'Redonda o cursiva.
colorColorValueel del texto generalEl color de las letras.
textTransform'none' | 'uppercase''none'Mayúsculas, como las que ponen los mapas a mares y países.
letterSpacingnumber0Espacio añadido entre letras, en ems.
halo{ color, width }ningunoUn contorno detrás de las letras, para que se lean sobre una imagen cargada.
background, paddingColorValue, DimensionningunoUna placa detrás del rótulo, y el espacio alrededor de su texto.
minScalenumber0.85Hasta qué tamaño se puede reducir un rótulo cuando no cabe en su ancho.

#Campos de rótulo de un anclaje

Los anclajes de una imagen (Resource.anchors, los puntos que usan los cómics para los hablantes) admiten unos pocos campos opcionales para rótulos. Son fracciones de la imagen, así que valen en todos los idiomas y con cualquier recorte de la imagen. Los cómics los ignoran.

CampoTipoPor defectoDescripción
widthnumberel propio del rótuloLa medida del rótulo, como fracción del ancho de la imagen: un nombre largo se parte en dos líneas dentro de ella.
align'start' | 'center' | 'end''center'Qué lado del rótulo queda en el punto del anclaje.
verticalAlign'top' | 'middle' | 'bottom''middle'Qué borde del rótulo queda a la altura del anclaje.
rotatenumber0Grados, en el sentido de las agujas del reloj, alrededor del punto del anclaje: el nombre de un río a lo largo de su curso.
stylestringningunoUn id de labelStyles. Un rótulo que nombra su propio estilo lo sustituye.

#Avisos de las plantillas de página

En el resto de la configuración, el motor ignora una clave que no conoce. Las plantillas de página y los estilos de rótulo, en cambio, se comprueban, y cada problema es un aviso de configuración en postext check y en el panel Revisión del Sandbox. El campo path de estos avisos es un puntero JSON al campo que falla: /pageTemplates/3/frames/2/style, /pageTemplates/0/variants/recto/frames/1/next, /resources/4/anchors/0/style. Cuando el campo es heredado, el puntero nombra la plantilla que lo escribió. Un aviso que nombra un id o un nombre que no existe propone además el existente que más se le parece.

Una clave mal escrita de una plantilla, un marco, un grupo, una rejilla, fit, overflow, una variante o un estilo de rótulo es un unknownConfigKey; una palabra fuera de las opciones de un ajuste (area, verticalAlign, exclude, takes, kind, align, writingMode, direction, fontStyle, textTransform) es un unknownConfigValue, y el ajuste conserva su valor por defecto. Una plantilla sin id, o un marco o un grupo sin name, se ignora con un unknownConfigValue en ese campo.

AvisoCausaSolución
templateDuplicateDos plantillas tienen el mismo id. Se usa la primera y la posterior se ignora.Cambia el nombre de una de ellas, o borra la copia.
templateExtendsCycleSiguiendo extends se vuelve a la misma plantilla (a → b → a). Todas las plantillas del ciclo, y todas las que extienden alguna de ellas, se descartan: ninguna página puede usarlas.Quita el extends de una plantilla del ciclo.
templateExtendsUnknownextends nombra un id que no tiene ninguna plantilla. La plantilla se usa sola, sin heredar nada.Corrige el id (el aviso propone el más parecido), o añade la plantilla padre.
frameDuplicateDos marcos, o dos grupos, de una misma lista tienen el mismo name, o un grupo tiene el nombre de un marco. La entrada posterior se ignora; un anclaje a ese nombre lee el marco.Da a cada marco y a cada grupo un nombre propio. Para cambiar un marco heredado, escribe una sola entrada con su nombre.
frameStyleUnknownEl style de un marco no nombra ningún estilo de aviso. El marco se dibuja sin caja.Corrige el id, o añade el estilo a calloutStyles.
frameAnchorUnknownUn marco, un grupo o un elemento de decoración está anclado a '#name' y la plantilla no tiene ningún marco, grupo ni elemento con ese nombre; o hay marcos y grupos anclados entre sí en un ciclo (también a través de un grupo sin anclaje propio, cuya caja es la de sus marcos). El anclaje se lee como 'container', el área.Ancla a un marco o a un grupo que exista, o rompe el ciclo anclando uno de ellos al área.
frameMinMaxUn mínimo es mayor que su máximo (minHeight 40mm > maxHeight 30mm), o un width o un height fijo queda fuera de ellos. Se impone el mínimo, un tamaño fijo se lleva dentro de los límites y used dice qué ocupa el marco. Las longitudes en unidades distintas se comparan a la resolución de la página, y los ems al cuerpo del texto general.Haz que el mínimo no supere al máximo, o quita el límite que contradice el tamaño fijo.
groupFrameUnknownLos frames de un grupo incluyen un nombre que no es ningún marco de la plantilla (quizá lo quitó una plantilla hija o una variante). El grupo se lo salta.Corrige el nombre, o quítalo de la lista.
groupFrameTwiceUn marco figura en dos grupos, o dos veces en uno. Un marco pertenece a un solo grupo: la aparición posterior se salta.Deja el marco en el grupo con el que se mueve.
frameChainLoopUnos marcos continúan unos en otros en un ciclo a través de next o de overflow.continueIn: '#frame' (a → b → a). El enlace que cierra el ciclo se descarta, así que la cadena termina en el marco anterior a él.Termina la cadena en su último marco: quítale el next, o haz que continúe en la página siguiente.
overflowTargetUnknownUn next no nombra ningún marco de la plantilla; un overflow.continueIn no nombra ningún marco ('#x') ni ninguna plantilla ('template:x'), o no tiene ninguna de las formas '#frame', 'next-page' y 'template:<id>'; o overflowTemplate no nombra ninguna plantilla. El contenido que no cabe no continúa allí.Corrige el nombre o el id, o escribe una de las tres formas.
labelStyleUnknownUn anclaje de una imagen nombra un style que labelStyles no tiene. El aviso nombra el recurso. Los rótulos de ese anclaje toman el aspecto por defecto.Corrige el id del estilo en el anclaje, o añade el estilo a labelStyles.

La versión de la configuración es la 15 desde las plantillas de página (los paquetes escritos antes se siguen cargando sin cambios: nada de lo que dice una configuración anterior cambia de significado).