MarkeUP: qué es, stack tecnológico y estructura del proyecto
Qué es MarkeUP: el sistema de publicación multiblog que convierte un vault de Obsidian en web, su stack tecnológico, la estructura de carpetas y el papel de Hermes Agent.
Navegando en el blogver navegación en todos los blogs
MarkeUP es un sistema de publicación multiblog que convierte un vault de Obsidian en un sitio web estático moderno. El contenido se escribe en Markdown dentro de Obsidian, se sincroniza al ordenador de build vía Syncthing, y se despliega en Cloudflare Pages mediante GitHub Actions. Además, integra Hermes Agent — un asistente de IA local (vía Ollama) que gestiona, crea, amplía y enriquece el vault de forma inteligente.
“En el móvil escribes, el Mac/PC construye, la nube sirve, y Hermes gestiona.”
| Capa | Tecnología | Propósito |
|---|---|---|
| Framework | Astro 4.16 | Generación de sitio estático (SSG) |
| CSS | TailwindCSS 3 + DaisyUI 4 | Componentes UI + 6 temas |
| Búsqueda | Pagefind 1.5 + grafo propio | Búsqueda offline con relevancia jerárquica y posts relacionados — ver doc-buscador |
| Grafo 3D | Three.js + 3d-force-graph | Visualización interactiva |
| Grafo 2D | D3.js | Grafo de relaciones alternativo |
| Imágenes | Sharp 0.33 | Crop + WebP responsivo |
| Smooth Scroll | Lenis 1.3 | Scroll suave táctil |
| Markdown | remark + rehype | Wikilinks `[[slug |
| Gestión IA | Hermes Agent v0.18.2 | Editor Jefe del vault: crear, ampliar, auditar, wikilinks |
| Motor LLM | Ollama + qwen2.5-coder:7b-64k | Inferencia local de lenguaje |
| Sincronización | Syncthing | Peer-to-peer Móvil ↔ Mac |
| CI/CD | GitHub Actions | Build + deploy automático |
| Hosting | Cloudflare Pages | CDN global |
Para la puesta en marcha paso a paso, consulta la guía de instalación; para los comandos del día a día, la guía de operación.
markeup/
├── src/
│ ├── generar_articulo.py ← Script: posts automáticos desde URLs con Ollama
│ ├── telegram_bot.py ← Bot de Telegram
│ ├── components/ ← 18 componentes Astro (blog/, common/, graph/)
│ ├── content/
│ │ ├── posts/ ← Colección de 63 posts en 5 categorías
│ │ │ ├── Humano/ ← 56 posts (bienestar, energía, filosofía)
│ │ │ ├── Documentación/ ← 5 docs del sistema
│ │ │ ├── Literatura/ ← 2 posts (Pessoa)
│ │ │ ├── Opinión/ ← 1 post
│ │ │ ├── Máquina/ ← 28 posts (dev, IA, herramientas)
│ │ │ ├── img/ ← Imágenes fuente
│ │ │ └── hermes/ ← 🆕 Sistema de gestión IA del vault
│ │ │ ├── SOUL.md ← Personalidad y reglas de Hermes
│ │ │ ├── memory/ ← vault-index, conventions, backlog
│ │ │ ├── skills/ ← crear, ampliar, wikilinks, auditar
│ │ │ ├── templates/ ← Plantilla de frontmatter (22 campos)
│ │ │ ├── rules/ ← Especificaciones YAML, wikilinks, estilo
│ │ │ └── logs/ ← Registro de sesiones
│ │ └── content.config.ts ← Schema Zod + loader glob
│ ├── layouts/BaseLayout.astro ← Layout único: OG tags, Breadcrumb, Lenis
│ ├── lib/ ← posts.ts, tags.ts, graph.ts, images.ts, remark-wikilink.js
│ ├── pages/ ← 16+ rutas (index, posts, category, tags, graph, search)
│ └── styles/ ← CSS modular (@layer base/components/utilities)
├── scripts/ ← process-images, optimize, sync, compress-audio, dev-search
├── public/ ← img (WebP), fonts, audpublic, pagefind
├── astro.config.mjs ← site, aliases, remark-wikilink, rehype-slug
├── src/styles/base.css ← Tailwind v4 (@plugin daisyui, 10 temas)
└── .github/workflows/ ← deploy.yml + lighthouse.yml
Hermes Agent es un asistente de IA que corre localmente sobre Ollama y gestiona el vault de forma inteligente:
| Función | Descripción |
|---|---|
| Crear posts | Genera notas con frontmatter YAML completo (22 campos), wikilinks inteligentes y estructura consistente |
| Ampliar posts | Expande contenido existente manteniendo tono y estilo |
| Gestionar wikilinks | Escanea notas, detecta conceptos enlazables, genera `[[slug |
| Auditar vault | Detecta huérfanos, inconsistencias, tags duplicados, sugiere mejoras |
| Mantener índice | memory/vault-index.md actualizado con 63 slugs, ~150 tags, ~100 huérfanos |
| Backlog | 22 ideas de posts priorizadas por demanda (huérfanos con más apariciones) |
hermes/
├── SOUL.md ← Personalidad: Editor Jefe, protocolo, reglas
├── memory/
│ ├── vault-index.md ← Índice vivo de TODOS los slugs, tags, huérfanos
│ ├── conventions.md ← Decisiones editoriales + correcciones pendientes
│ └── backlog.md ← 22 ideas priorizadas de posts a crear
├── skills/ ← Flujos de trabajo detallados
│ ├── crear-post.md ← 11 pasos: desde tema hasta backlinks
│ ├── ampliar-post.md ← Expansión de notas existentes
│ ├── generar-wikilinks.md ← Escaneo inteligente + diffs
│ ├── auditar-vault.md ← Auditoría completa con informe
│ └── documentar.md ← 🆕 Verifica que la doc refleje la realidad
├── templates/
│ └── post-template.md ← Plantilla YAML con 21 variables
├── rules/
│ ├── frontmatter-spec.md ← Especificación de cada campo
│ ├── wikilinks-spec.md ← Reglas de alias
│ └── style-guide.md ← Tono, estructura, formato, SEO
└── logs/sessions/ ← Trazabilidad de cada acción
# Iniciar Hermes (requiere Ollama corriendo)
hermes chat
# Ejemplos de comandos:
# "Crea un post sobre meditación vipassana en categoría Humano"
# "Amplía el-grounding.md con una sección sobre técnicas de enraizamiento"
# "Revisa los wikilinks de el-aura.md"
# "Audita el vault"
# "¿Qué posts debería crear primero?" → consulta el backlog
- 🆕 Editor Jefe IA con SOUL, reglas, skills y memoria persistente
- 🆕 Índice automático del vault (63 slugs, ~150 tags, ~100 huérfanos)
- 🆕 Backlog de 22 ideas de posts priorizadas
- 🆕 Protocolo LEER → ANALIZAR → PROPONER → CONFIRMAR → ESCRIBIR → LOGUEAR → INDEXAR
- BreadcrumbList JSON-LD, Open Graph completo, Twitter Cards, sitemap, RSS
- Imágenes responsivas (srcset 640w-1920w), preload LCP, font-display swap, CSS @layer
- 6 temas DaisyUI, glassmorphism, Lenis smooth scroll, grafos 3D/2D, Pagefind search
- 97 posts en 5 categorías
- Wikilinks con alias descriptivo:
[[slug|alias]](obligatorio en párrafos;[[slug]]solo se tolera en headings, tablas y bloques de código) - Frontmatter YAML de 22 campos validado con Zod y con los validadores del repo (
npm run validate:frontmatter·npm run validate:seo)
/privacy— Política de privacidad RGPD/LOPD (10 secciones con índice lateral)./terms— Términos de uso (licencias, propiedad intelectual, enlaces externos, cookies, ley aplicable)./faq— Preguntas frecuentes desplegables (plataforma, contenido, cookies, RSS, búsqueda).- Footer con enlaces legales + aviso coherente a
robots.txty legal.
rel="canonical"en cada página (auto-canonical desde la URL actual).- Open Graph completo:
article:published_time,article:modified_time,article:author,article:section,article:tag(cada tag), ymeta name="author"en los posts. - Twitter Cards completas:
twitter:card=summary_large_image,twitter:title/description/image/image:alt/url/domain/image:width/heightytwitter:site/twitter:creator=@splitzforx(constanteTWITTER_HANDLEenBaseLayout). Imagen OG por defecto 1200×630 (ratio 1.91:1). - Schema.org BlogPosting enriquecido: fecha ISO,
inLanguage, author comoPerson[]consameAsa X, publisher organizacional conlogo, image array yarticleSection. - Robots + sitemap + RSS renovados: robots con grupos por crawler, sitemap con
changefreq, feed RSS con<image>, autor por item y alias/rss,/feed. - Alt-text y accesibilidad:
imageAlt/og:image:alt, skip-link «Saltar al contenido»,focus-visiblevisible, un único<main>por página y script de auditoríaa11y-check.mjs.
- Botones de compartir en cada post: X, LinkedIn, Facebook, WhatsApp, Telegram + copiar enlace.
- Todas las URLs son absolutas (
https://markeup.pages.dev/posts/slug); las redes no resuelven rutas relativas y el enlace llegaría roto (bug corregido). - Web Share API: en móvil abre el panel nativo de compartir; degrada a los enlaces por red en escritorio.
- Lógica en
src/lib/social-share.ts(testeable) + componenteSocialShare.astro. - Validación:
npm run validate:shareaudita OG, Twitter Cards y URLs de compartir endist/.
- Banner de cookies
CookieConsent(solo esenciales/aceptar), sin trackers; guarda tu elección enlocalStorage.
- Rich tooltips (hover-preview): al pasar el ratón sobre wikilinks internos
[[slug]]o enlaces/posts/*del cuerpo se muestra una tarjeta con imagen, categoría, autor·fecha, minutos de lectura, descripción y CTA. - Coreografía de apertura «la tarjeta se materializa y su foto se abre» (GSAP, ≈0,8 s, beats solapados): la tarjeta se construye de una pieza, se mide una sola vez (a su tamaño final) y entra con una
gsap.timeline():- La tarjeta se materializa (
opacity+scale0,965→1 +y12 px desde el lado en el que está el enlace) y el bloom de luz se enciende. - Metadatos y título entran ya con ella, el título palabra a palabra (
stagger24 ms). Arrancan a los 20/50 ms y no cuando la foto está abierta porque, si esperasen, durante los primeros ~150 ms se vería un panel vacío (la foto está tapada por la cortina y el texto aún oculto). - La foto se abre por cortina:
clip-path: inset(100% 0% 0% 0%)→inset(0% 0% 0% 0%)(de abajo arriba) mientras la miniatura se asienta (scale1,14 → 1) y un reflejo la cruza una sola vez. - Descripción (sube) y CTA con su flecha, que se mece en bucle cuando la entrada termina.
- La tarjeta se materializa (
- Por qué va fino (contrato de suavidad): solo se animan
transform,opacityyclip-path; ni una propiedad de layout (width,height,top,left…). Animar el tamaño de una caja obliga a re-maquetarla y repintarla en cada frame: era la causa de los tirones. Además: sinbackdrop-filteren la tarjeta (obliga a re-muestrear el fondo cada frame), tamaño medido una sola vez,will-changesolo mientras dura la entrada (clase.lp-anim, se retira al terminar para no dejar capas vivas) y beats solapados (la foto se abre mientras el texto sube), así que no hay pausas. Medido en Chrome real connpm run verify:preview: p50 ≈ 17 ms (60 fps), p95 ≈ 18 ms, sin picos. - El estado por defecto del CSS es el FINAL: los estados iniciales los aplica GSAP en la misma tarea en la que se monta la tarjeta (
fromTo), así que no hayopacity: 0en el CSS ni FOUC. Si falta GSAP, si el navegador no soportaclip-path: inset()o si el usuario pideprefers-reduced-motion, la tarjeta aparece ya completa: el plan B no necesita código. - Cambio de enlace: una sola tarjeta que viaja: al pasar de un enlace a otro no se monta otra tarjeta: la misma vuela al enlace nuevo (
transformpuro desde la posición anterior), cambia su contenido y vuelve a revelarlo (la cortina de la foto se cierra y se abre otra vez). Así no hay ni un frame con dos tarjetas, ni parpadeo de la imagen, ni un contenedor a medias tapando el enlace recién hovereado. La timeline es única por tarjeta (killTl(node)): el cierre de una no puede tocar la animación de otra. Y si el puntero cae sobre la tarjeta,underPop()la aparta un instante del hit-test y pregunta qué hay debajo: si es otro enlace con preview, se atiende igual, así que no hay que apartar el ratón para hoverear un enlace tapado. - Colocación: la tarjeta se mide una vez (no cambia de tamaño, así que lo medido es lo que se verá) y se coloca arriba o abajo del enlace, con recorte final: nunca se sale del viewport, ni con el enlace pegado a un borde o fuera de pantalla. Al hacer scroll se recoloca; si el ancla sale de la vista, se cierra. La miniatura se precalienta con
decode()fuera del hilo principal para que su decodificación no caiga dentro del primer frame de la animación. - Alcance: el tooltip atiende los enlaces del cuerpo (
.prose), los wikilinks y cualquier enlace marcado condata-preview="on". Eso incluye las píldoras de «Posts que enlazan a este artículo», que viven fuera del cuerpo: la plantilla del post las marca en el HTML servido (src/pages/posts/[...slug].astro) ysetBacklinks()(src/lib/section-nav.ts) las marca al re-renderizarlas cuando se entra con?from=. Quedan fuera a propósito las tarjetas de listado (.post-card, que ya son una tarjeta), los botones/CTAs y las flechas anterior/siguiente. - GSAP se sirve como global:
preview.jses un script estático depublic/(sin imports), así que el layout cargapublic/vendor/gsap.min.js(build UMD) antes que él. Se mantiene sincronizado connpm run vendor:gsap(y--checken el build). - Rich format cards:
![[slug]](embebido Obsidian) se convierte en una tarjeta rica enlazable dentro del artículo. - Implementación en
public/preview.js(lógica) +src/styles/rich.css(estilos), datos del manifiesto/api/posts.json. Cubierto porsrc/lib/preview-choreography.test.ts(contrato de suavidad: ni una propiedad de layout, tamaño constante, miniatura porscale, orden y solape de los beats, título palabra a palabra, reutilización de la tarjeta al cambiar de enlace, enlace tapado, plan B sin GSAP y auditoría del propio CSS) y verificado en navegador real connpm run verify:preview(Chrome headless vía CDP: tamaño constante en cada muestra, cortina 100%→0%, cascada del texto, ritmo de frames y escena 2 con el salto entre dos enlaces contiguos; capturas en/tmp/lp-shots/).
/llms.txt— archivo estándarllmstxtpara consumidores de IA (página principal + lista de posts)./api/posts.json— manifiesto JSON ligero de todos los posts (slug, título, descripción, metadatos, minutos) usado por previews y agentes.
- Diseñada con sugerencias de categorías, botones de navegación y
<meta noindex>para no ensuciar el índice.
| Documento | Contenido |
|---|---|
| doc-guia-MarkeUp | Instalación y configuración (Syncthing, Obsidian, Templater, Ollama) |
| doc-arquitectura-MarkeUp | Arquitectura: árbol de archivos, flujo de build, componentes, CSS, CI/CD |
| doc-operacion-MarkeUp | Comandos, scripts, troubleshooting, Hermes Agent |
| Publicación Automática | Publicar con un solo comando y autopublicación automática móvil → web |
| doc-auditoria-MarkeUp | Estado actual, deuda técnica, plan de mejoras, métricas |
1 PROCESOS
├── 1.1 PROCESOS OLLAMA (iniciar, cambiar modelo, estado, detener)
├── 1.2 PROCESOS TELEGRAM (iniciar/detener bot)
├── 1.3 PROCESOS HERMES (lanzar, reanudar, cambiar modelo)
└── 1.4 ARRANCAR Ollama + Telegram
2 VAULT → 2.1 ANÁLISIS DEL VAULT (auditar, huérfanos, stats, docs...)
3 CONTENIDO DEL VAULT (crear, generar artículo, ampliar, wikilinks...)
4 BUILD & ASSETS
├── 4.1 PROCESAR IMÁGENES Y AUDIOS
├── 4.2 BUILD (completo, preview, pagefind)
├── 4.3 DEV SERVER (local, network)
└── 4.4 NPM (8 comandos útiles)
5 GIT
├── 5.1 Ramas (creación y cambio)
├── 5.2 Ramas (limpieza y fusión)
├── 5.3 Estado y preparación
├── 5.4 Commits y deshacer
├── 5.5 Stash
└── 5.6 Remoto
6 CLOUDFLARE
├── 6.1 Autenticación y proyectos
└── 6.2 Despliegues (preview, producción, rama)
7 MANTENIMIENTO (renombrar, mover, limpiar, exportar, docs)
8 STATUS (posts, git, build, Ollama, assets)
Documentación relacionada: la auditoría y la arquitectura para el detalle técnico, y la guía de Vault CMS.
Este territorio conecta con Focusing, donde se explora eugene Gendlin y el Focusing: la experiencia sentida (Felt Sense) como puente entre la emoción, la intuición y la.
doc-readme-MarkeUp
Explora las ramas del artículo
