Documentación Libellus
URLs del sitio (Netlify / dominio)
- Producción (canónica):
https://marconoris.com - Netlify (deploys):
https://marconoris.netlify.app - Aliases:
https://libellus.marconoris.comhttps://marconoris.art
Enlaces de la bóveda de Obsidian
- Los enlaces relativos que salen de este repo (p. ej.
../../../Lecturas/...) se reescriben automáticamente durante el build. - Configura el host de publicación con
obsidian_publish_baseurlen_config.yml(actualmentehttps://lab.marconoris.com). - Cualquier enlace Markdown o atributo HTML
href/srcque empiece por../se reescribe hacia ese host, para que los assets exportados de la bóveda sigan funcionando en la web. - Documentación técnica de los plugins:
OBSIDIAN-PLUGINS.md.
Cómo mantener el sitio
Checklist rápido para que todo funcione bien:
- Front matter mínimo:
layoutcorrecto (post/page/project…),title,date,lang(es/ca/en/it…). Sintitleno aparece en listados; sinlangel pager asumees. - Slugs/URLs: no necesitas tocarlos; el hook genera
sluglatinizados y permalinks por colección. Usaslug/permalinksolo si quieres forzar algo distinto. - H1 y contenido: si el documento incluye un
#(H1) en el cuerpo, los layouts inyectan elmeta-infojusto después de ese H1 (sin tocar el Markdown). Si no hay H1 en el cuerpo, el layout pinta un H1 de fallback contitle/heading. - Índice (TOC): añade
show_toc: trueen el front matter depostopagepara mostrar un índice lateral (H1/H2/H3) en pantallas anchas. - Paginación/pagers: el include
pagination.htmlmuestra anterior/siguiente dentro de la mismacollectionylang. Si no ves pager, compruebalang. - Orden en colecciones:
- Projects: se ordenan por fecha (descendente). Si quieres posicionar manualmente, usa
ordery/o ajustadate. - Resto de colecciones: si tienen
order, se ordenan pororder(ascendente) y, a igualdad, por fecha descendente. Si no hayorder, solo por fecha.
- Projects: se ordenan por fecha (descendente). Si quieres posicionar manualmente, usa
- Callouts: usa sintaxis
> [!tipo] Título(tip, success, warning, danger, quote, cite, question, note, links, abstract, summary, texts…). Mira/callouts-demo/para ejemplos. - Autolink de URLs: cualquier http/https suelto se enlaza automáticamente en el post-render. Si necesitas desactivar en una página/post, pon
autolink_urls: falseen el front matter. - Build limpio: si cambias permalinks/slugs, borra
_sitey.jekyll-cachey ejecutabundle exec jekyll build(sin incremental) para ver los cambios.
Bio site (“link in bio”)
- Documentación técnica:
BIO-SITE.md.
Embeds de vídeo (YouTube/Vimeo/Bunny) y allowlist
El plugin _plugins/video_markdown_embed.rb convierte URLs de YouTube, Vimeo y Bunny Stream en iframes responsivos cuando:
- Pegas una URL “sola” en una línea (ej.
https://vimeo.com/974390692). - Usas sintaxis de imagen Markdown apuntando a la URL del vídeo: `<div class="video-embed video-embed--vimeo">
</div> (el texto se usa como title` del iframe).
- Para Bunny Stream, la forma canónica es
https://player.mediadelivery.net/play/<library>/<video-guid>.
Cómo funciona la allowlist
Para evitar pasar parámetros arbitrarios al embed, el plugin:
- Lee el querystring de la URL original (lo que va tras
?). - Conserva solo las claves permitidas por plataforma (
ALLOWED_QUERY_PARAMS), normalizando el nombre a minúsculas. - Descarta cualquier otro parámetro.
Allowlist actual:
- YouTube:
autoplay,controls,loop,mute,playsinline,start,end - Vimeo:
autoplay,loop,muted,autopause,playsinline,background,dnt,title,byline,portrait,badge - Bunny Stream:
autoplay,captions,preload,t,chromecast,disableAirplay,disableIosPlayer,showHeatmap,muted,loop,playsinline,showSpeed,rememberPosition,responsive
Además, para Vimeo el plugin añade por defecto title=0&byline=0&portrait=0&badge=0 (puedes sobrescribirlos si los pasas en la URL y están en la allowlist).
Otros iframes responsivos (mapas, álbumes, etc.)
Si necesitas embeds que no sean 16:9 (Lightroom, Mapbox, Sketchfab…), envuélvelos en .embed-frame y marca el ratio con --embed-ratio (fallback 4/3):
<div class="embed-frame" style="--embed-ratio: 4 / 3">
<iframe src="https://…"></iframe>
</div>
El wrapper elimina el margen del iframe, hereda el radio de borde y mantiene la relación de aspecto que definas.
Para colocar varios iframes uno al lado del otro, usa .embed-grid como contenedor:
<div class="embed-grid">
<div class="embed-frame" style="--embed-ratio: 4 / 3">
<iframe src="https://…"></iframe>
</div>
<div class="embed-frame" style="--embed-ratio: 4 / 3">
<iframe src="https://…"></iframe>
</div>
</div>
Portadas con video de fondo
El layout cover (ver portada.md) admite video de fondo desde Vimeo, YouTube o Bunny Stream. Usa cover_video o video_cover (también vale cover_vimeo para compatibilidad) con la URL completa:
layout: cover
title: ...
cover_video: https://vimeo.com/123456789
# o https://youtu.be/abc123
# o https://player.mediadelivery.net/play/617291/d545466f-50c1-4c37-9919-8f2818c78aed
# Opcional: cover (imagen) como fallback estático
El layout ajusta parámetros para autoplay/loop/mute y oculta los controles. No hace falta width/height; el iframe se adapta a la sección hero.
Si quieres random por visita, cover_video también acepta lista (en singular):
cover_video:
- https://vimeo.com/123456789
- https://youtu.be/abc123
cover_videos también funciona por compatibilidad, pero cover_video es la forma recomendada.
Imágenes sociales para páginas con cover
cover sigue siendo la única propiedad de front matter para la portada principal. No hace falta añadir otra propiedad para compartir.
Cuando cover apunta a un .webp local, la social card busca automáticamente una derivada JPG en el mismo directorio con este patrón:
basename.webp -> basename.social.jpg
Ejemplos:
images/tizas.webp->images/tizas.social.jpgimages/news/ElDorado-hor.webp->images/news/ElDorado-hor.social.jpg
Si la derivada existe, se usa para og:image y twitter:image. Si no existe, la plantilla cae a la imagen social global por defecto.
Para generar o regenerar estas derivadas:
python3 script/generate_social_images.py --dry-run
python3 script/generate_social_images.py
El script:
- recorre el contenido y detecta
cover.webplocales referenciados - genera
*.social.jpga1200x630 - no reescribe front matter
- no sobrescribe el
.webporiginal
Usa --force si quieres regenerar todo aunque la derivada ya exista.
Random de cover (video)
Cuando cover_video es una lista, el layout cover puede elegir el video:
visit(por visita/carga de página, default)session(una vez por sesión de navegador)day(una vez por día, según la hora local del usuario)
Configúralo en el frontmatter con cover_video_random: visit|session|day.
Frontmatter para Jekyll
Lo mínimo que necesita cada tipo de documento para que todo funcione sin sorpresas:
- layout: el adecuado para la colección (post, page, project, etc.).
- title: obligatorio (sin título no sale en listados ni en Home/collections).
- date: para ordenar (posts y colecciones); si falta, caen a orden 0 o usan updated.
- lang: consistente (es/ca/en/it…). El pager filtra por lang y si falta asume es.
Opcional según necesidad:
- slug/permalink: los genera el hook a partir de title, así que solo hace falta si quieres forzar algo distinto.
- year: en projects para ordenar por año antes que por fecha.
- order: en projects para ordenar dentro del mismo año.
- publish: false para ocultar.
- hide_h1: true si quieres ocultar el H1 de fallback del layout (cuando el documento no trae H1 en el cuerpo).
- libellus_featured: true para fijar publicaciones en la home de Libellus de Libellus.
- featured: true para incluir el documento en los bloques de destacados del
indexmultilengua y delbiosite. - featured_order: orden manual ascendente dentro de esos bloques. Si falta, se usa
updatedy luegodatecomo fallback. - year_range_sort: en índices con
layout: seriescontrola cómo ordenar rangos enyear(startpor defecto;endusa el último año del rango). -
external_links: lista de enlaces externos (por ejemplo VSCO/Are.na) que se renderizan al final de los layouts
project/project-two-column.external_links: - label: VSCO url: https://vsco.co/... - label: Are.na url: https://www.are.na/...
Clases y estilos rápidos en Markdown (kramdown/Liquid)
- Atributos kramdown al final de un párrafo o imagen:
Texto aquí {: .project-text }o!Alt{: .img-blend }. - Anchos puntuales sin tocar CSS:
!Alt{: style="width: 260px;" }o envolviendo:<div style="width:260px">!Alt</div>. - Múltiples clases o estilos:
{: .project-text .resalte style="max-width: 18rem;" }. - Recuerda que la sintaxis va pegada al elemento anterior (sin línea en blanco) y se procesa antes que el Markdown/HTML del layout.
Portada / home
- Home principal (index
es/ca/en/it): el bloque “Destacado” (vía_includes/home-index-featured.html) mezclasite.pagesy todas las colecciones, filtrando porlangy excluyendopublished: false/publish: false. - Propiedades de selección (home principal):
featured: true= incluye el documento en destacados.featured_order= orden manual ascendente.- deduplicación por
translation_key(ourlsi falta). - si no hay
featured_order, fallback temporal porupdateddesc y, si no hayupdated,datedesc.
- Bloque “Studio shop” (home principal):
- Se renderiza vía
_includes/home-shop.htmlcon datos en/_data/shop_featured.yml. - Por defecto muestra 4 items (2x2 en mobile, 4 columnas en desktop).
- Apagar en una home concreta:
home_shop: falseen el front matter delindex.mdcorrespondiente. - Idiomas: cada item puede llevar
lang: es|ca|en|it; si falta, aparece en todos los idiomas. - Labels i18n:
home_shop_title(título del bloque) yhome_shop_all(CTA “ver tienda”).
- Se renderiza vía
- Home de Libellus:
libellus_featured: truese mantiene para su bloque destacado específico. -
Colapsar colecciones: hay un bloque
collections_statecomentado en_config.yml; por defecto todas quedan cerradas. Lista enopenlas que quieras abrir de inicio:collections_state: open: - posts - versiculipuedes listar las colecciones a ocultar sin borrarlas. Úsalo si decides implementar lógica de cierre en los listados/pagers.
Shop featured data (/_data/shop_featured.yml)
Estructura recomendada (4 items por idioma, títulos localizados; URLs e imágenes pueden reutilizarse):
items:
- title: "Obra original"
url: "https://shop.marconoris.com/category/obra-original"
image: "https://assets.bigcartel.com/product_images/.../foo.jpg"
lang: es
- title: "Original artwork"
url: "https://shop.marconoris.com/category/obra-original"
image: "https://assets.bigcartel.com/product_images/.../foo.jpg"
lang: en
Campos:
title(texto visible)url(destino enshop.marconoris.com)image(URL remota o ruta local/images/...)price(opcional, string)lang(opcional; si falta, aparece en todos los idiomas)
Bio site (layout: biosite)
- El layout está en
_layouts/biosite.htmly se usa enpages/*/bio.md. - Al final del bio (antes del logo de cierre) renderiza el mismo bloque de shop (
_includes/home-shop.html). - Apagar en una bio concreta:
bio_shop: falseen el front matter depages/*/bio.md.
Galerías (PhotoSwipe)
Guía rápida para usar las galerías del layout project y sus opciones:
-
Galería única “suelta” (lo básico): si solo necesitas una galería, puedes definirla directamente en el documento (sin
galleries:). Conlayout: projectse renderiza automáticamente (a menos que usesgallery_render: manual).gallery_style: grid # opcional (default: grid) gallery: - src: /images/projects/mi-proyecto/01.webp caption: "Pie opcional" - src: /images/projects/mi-proyecto/02.webpo bien auto desde carpeta:
gallery_style: masonry # opcional gallery_path: /images/projects/mi-proyecto/ # importante: con barra final gallery_caption_all: "Mi caption" # opcional # gallery_captions: # opcional (mapa filename -> caption) # 01.webp: "Pie 1" # 02.webp: "Pie 2" -
Múltiples galerías (recomendado si quieres títulos/secciones): define
galleries:como lista de bloques. Cada bloque aceptaid,gallery_style(grid,masonry,collage,carousel), ygallery(lista de imágenes consrc; opcionales:thumb,caption,width,heightpara el zoom del lightbox):galleries: - id: uno gallery_style: masonry gallery: - src: ../images/foo/bar.webp thumb: ../images/foo/bar-thumb.webp caption: "Título o pie" width: 1800 height: 1200 - Auto desde carpeta: en lugar de listar imágenes, usa
gallery_path: /images/projects/mi-proyecto/(incluye la barra final) para cargar todos los ficheros de esa carpeta (ordenados por nombre). Puedes añadirgallery_captions:para sobrescribir captions por archivo. Si quieres el mismo caption para todas las auto, usagallery_caption_all: "Mi caption". - Render: por defecto (
gallery_render: auto) el layout recorregalleries(ogallery/gallery_pathsueltas) y pinta la galería antes del contenido. - Incrustar la galería en el Markdown (manual):
1) En el front matter añadegallery_render: manualy define la galería congalleries:(ogallery:/gallery_path:si solo hay una):gallery_render: manual galleries: - id: swab gallery_style: masonry gallery: - src: ../images/news/swab.webp caption: "Obra en SWAB"2) En el cuerpo del
.mdcoloca el include donde quieras que aparezca:{% include project-gallery.html id="swab" %}Si solo tienes una galería suelta (
gallery:en front matter), no hace faltaid.
3) Títulos y descripciones de la galería: añadetitle:y/odescription:dentro del bloque de la galería (no en el front matter principal); se muestran encima del grid/carrusel sishow_metaestá activo (por defecto lo está). - Lightbox:
- Lightbox:
- Por bloque (default): cada bloque lleva su propio
data-pswp-gallery, el lightbox solo recorre esa galería. -
Global por página: envuelve varias galerías en un contenedor con
data-pswp-gallery="algo"y pasaskip_pswp_container=trueen cada include, para que compartan el mismo lightbox:<div data-pswp-gallery="project-foo"> {% include project-gallery.html id="uno" skip_pswp_container=true %} {% include project-gallery.html id="dos" skip_pswp_container=true %} </div> - Desactivar lightbox: pon
lightbox: falseen el bloque o en el include: `
- Por bloque (default): cada bloque lleva su propio
`.
-
Columnas por breakpoint (grid y masonry): usa
gallery_columns(móvil/base),gallery_columns_md(≥640px) ygallery_columns_lg(≥1024px). Ejemplo:gallery_columns: 1 gallery_columns_md: 2 gallery_columns_lg: 4Si no defines nada, se usan los valores por defecto del CSS (
grid:auto-fit;masonry: 1/2/3 columnas en móvil/≥640/≥1024). -
Notas de estilo: en
masonrylas imágenes no se recortan; si solo hay 1–2 imágenes se ajustan las columnas para ocupar el ancho (a menos que fijes columnas).collageusa filas fijas con spans;carouselcentra y permite scroll horizontal con controles. Puedes mezclargallerymanual congallery_path: las manuales se renderizan primero y luego las auto.
Bloques de logos (sponsors/partners)
Para un bloque de sponsors con logos centrados usa las clases project-sponsors:
<div class="project-sponsors">
<p class="project-sponsors__eyebrow">
Proyecto producido con el apoyo de <strong>BCN Producció 17</strong>. En colaboración con:
</p>
<div class="project-sponsors__grid">
<a class="project-sponsors__logo" href="https://lacapella.barcelona" target="_blank" rel="noopener">
<img src="https://lab.marconoris.com/images/logos/lacapella.png" alt="La Capella">
</a>
<div class="project-sponsors__logo">
<img src="/images/logos/mume.png" alt="MUME. Museu Memorial de l'Exili">
</div>
<div class="project-sponsors__logo">
<img src="https://lab.marconoris.com/images/logos/598.png" alt="Mojones de los Pirineos">
</div>
</div>
</div>
Usa rutas relativas a tus imágenes y ajusta los alt de cada logo. Todos los logos son HTML puro para evitar problemas de parsers Markdown mezclados.
Referenciar un proyecto desde páginas/posts
- Añade en el front matter
project_ref: <translation_key-del-proyecto>(ej.project_ref: lugares-remotos). - En los metadatos se mostrará
AÑO · Proyecto <link>(etiqueta traducida segúnlang). Busca el proyecto ensite.proyectosportranslation_keyy prioriza el mismolang; si no existe, usa el primero disponible. - Si quieres relacionar un contenido con una serie, usa
series_ref: <translation_key-de-la-serie>(acepta string o lista).project_refqueda reservado para proyectos.
Márgenes de texto en proyectos (override desde Markdown)
En páginas con layout project, el CSS aplica en desktop (≥768px) un margen lateral a los bloques de texto dentro de .project-content:
- Se aplica por defecto a
p,ulyolcomo hijos directos de.project-content. - Los párrafos que contienen contenido “media/interactive” (por ejemplo
img,iframe) se excluyen por defecto para evitar layouts raros (lospque envuelvenbuttonno se excluyen).
Si necesitas control fino desde Markdown (kramdown), puedes añadir clases a un bloque:
- Forzar el estilo “texto con márgenes” (aunque sea un bloque especial):
{:.project-text}(también usable enseries/page) - Quitar márgenes (ancho completo):
{:.project-text--full}
Ejemplos:
Este párrafo irá con margen lateral en desktop.
{:.project-text}
- Esta lista irá a ancho completo
- (sin margen lateral)
{: .project-text--full}