Automata Portfolio | Automata
secciones (10)
$ cd .. // volver a proyectos
automata@latam: ~/proyectos/automata-portfolio
PRODUCTO · slug: automata-portfolio ·2026 · 4 min read · 965 words

> Automata Portfolio

// Este sitio. Portfolio estatico Astro 5 + 9 case studies con estetica terminal, diagramas Mermaid en vivo, busqueda Cmd+K, syntax highlighting server-side y un solo translations.ts como fuente de datos.

Astro 5TypeScriptTailwind CSS 4MermaidShikiGSAPLenisPlaywright
forks last commit
Automata Portfolio
▸ rol
Diseño · FE · Infra · Contenido
▸ tiempo
~1 semana de sprints (con LLM pair)
▸ equipo
Solo
▸ status
online
// section 01 · descubrimiento

$ cat ./descubrimiento.md

▸ descripcion

Sitio portfolio + case studies de Automata. Cada proyecto vive como un objeto en src/i18n/translations.ts; la ruta [slug].astro renderea el template de 10 secciones a partir de esa data, asi agregar un proyecto es una edicion tipada, no un archivo nuevo. Los diagramas Mermaid cargan lazy desde un CDN con un theme custom que matchea el resto del sitio. Los code blocks se resaltan server-side con Shiki (cero JS al cliente para highlighting). Bilingue: EN en /, ES en /es. El sitio es un build estatico que deploya via GitHub Actions FTP.

▸ problema

Notion-as-portfolio y los templates de Webflow se ven igual que los de todos, y Linktree no muestra depth tecnica. La idea es ser evidencia de craft, no una lista de skills — y agregar un proyecto nuevo editando un registro tipado, no armando un CMS.

▸ audiencia

Clientes potenciales (CTOs, founders) que evaluan a Automata, mas recruiters tecnicos que necesitan ver depth real en menos de cinco minutos.

// section 02 · diseño

$ cat ./diseño.md

▸ herramientas
Figma (mockups)VS Code (design-in-code)Excalidraw (sketches C4)
▸ sistema de diseño
  • · JetBrains Mono en todo el sitio, ligatures activos
  • · Paleta: #000 / #0D1117 panel / #4ADE80 verde / #06B6D4 cyan / #FBBF24 amber
  • · Gramatica de prompt: $ ▸ ○ // como puntuacion visual
  • · Window-chrome (puntos ● ● ●) en cada panel
  • · Border-color como hover state — sin shadows, sin gradients
// section 03 · arquitectura

$ cat ./arquitectura.md

// section 04 · infraestructura

$ cat ./infraestructura.md

▸ servicios
provider: Astro 5 SSG + CDN edge
  • astro build (Sharp para optimizar imagenes)
  • Export estatico: HTML + assets, sin runtime Node en produccion
  • Hosting: cualquier static (FTP a shared host hoy; compatible con Vercel/CF Pages)
  • Plausible analytics (sin cookies)
  • Formspree para el form de contacto
  • API de GitHub via fetch en cliente para stars/forks/last commit en los headers de proyecto
  • Mermaid lazy-load desde esm.sh; Shiki corre en build time
// section 05 · implementacion

$ cat ./implementacion.md

▸ frontend
  • · Astro 5.16 (islands, SSG)
  • · TypeScript (strict)
  • · Tailwind CSS 4
  • · GSAP + ScrollTrigger
  • · Lenis (smooth scroll)
▸ backend
  • ·
  • · (estatico, sin runtime)
▸ datos
  • · translations.ts (registro en memoria, EN + ES)
  • · API de GitHub (fetch en vivo)
  • · Formspree (submissions de form)
▸ ia
  • · Shiki (syntax highlighting, server-side)
  • · Mermaid (rendering en vivo)
  • · Claude Code (pair LLM en cada sesion)
▸ devops
  • · GitHub Actions (CI: typecheck + build + Playwright)
  • · GitHub Actions FTP deploy en push a main
  • · Script de auditoria i18n (tools/i18n-audit.mjs)
// section 06 · desafios tecnicos

$ cat ./challenges/*.md

// 4 problemas tecnicos resueltos

01 / 04
challenge-01.md · astro · compiler · patrones
▸ problema

Astro rechaza <slot name={dynamic} /> dentro de un .map() — los nombres de slot deben ser literales en parse time.

restriccion: MasterDetail necesita renderear un pane distinto por item, pero Astro no compila un named slot dinamico.

▸ enfoque

Invertir el contrato: MasterDetail expone un solo default slot; los callers marcan cada pane con data-md-key. Un script chico en MasterDetail toggle visibility en base a ese atributo. El error de compile se fue, el caller queda explicito.

src/components/MasterDetail.astro astro
<!-- Generico: no sabe que va en cada pane -->
<div class="md-grid" data-masterdetail>
  <nav>{items.map((it, i) => (
    <button data-md-pick={it.key} data-active={i === 0}>{it.label}</button>
  ))}</nav>
  <div><slot /></div> <!-- el caller mete <div data-md-key="..."> aca -->
</div>

<!-- Caller: explicito, type-safe -->
<MasterDetail items={levels}>
  <div data-md-key="context"><MermaidViewer ... /></div>
  <div data-md-key="container" class="hidden"><MermaidViewer ... /></div>
</MasterDetail>
challenge-02.md · frontend · scroll · css
▸ problema

Un carousel con scroll-snap se pelea con Lenis smooth-scroll y vuelve siempre a la slide 0.

restriccion: Queriamos scroll horizontal nativo, snap perfecto y compatibilidad con Lenis. Las tres no se pueden.

▸ enfoque

Sacar scroll-snap del todo. El track translada via transform: translateX(-N * 100%). El wrapper es overflow:hidden — no hay scroll real, asi que Lenis no tiene nada que secuestrar. Flechas, dots y arrow keys actualizan el mismo indice.

src/components/Carousel.astro typescript
const update = (i: number) => {
    current = Math.max(0, Math.min(slides.length - 1, i));
    track.style.transform = `translateX(-${current * 100}%)`;
    counter.textContent = String(current + 1).padStart(2, "0");
    dots.forEach((d, di) => d.setAttribute("data-active", String(di === current)));
    if (prev) prev.disabled = current === 0;
    if (next) next.disabled = current === slides.length - 1;
};
challenge-03.md · css · grid · shiki
▸ problema

Un grid con sidebar sticky + code blocks explota el viewport horizontalmente.

restriccion: min-width:auto por default en grid items les deja crecer al tamaño de su contenido. Los <pre> largos de Shiki fuerzan al grid a ser mas ancho que 1fr.

▸ enfoque

Cambiar grid-template-columns de [200px 1fr] a [200px minmax(0, 1fr)], agregar min-w-0 al item de contenido. Los code blocks scrollean adentro, el grid mantiene su ancho.

src/components/ProjectDetail.astro html
<!-- Antes: explota -->
<div class="lg:grid lg:grid-cols-[200px_1fr]">
  <aside>...</aside>
  <div>...code blocks desbordan el grid...</div>
</div>

<!-- Despues: contenido -->
<div class="lg:grid lg:grid-cols-[200px_minmax(0,1fr)]">
  <aside>...</aside>
  <div class="min-w-0">...code blocks scrollean adentro...</div>
</div>
challenge-04.md · mermaid · theming
▸ problema

Los diagramas C4 de Mermaid llegaban con fills azul/gris hardcodeados que ningun themeCSS sobrescribia.

restriccion: C4Context/Container/Component pintan shapes con atributos SVG inline (fill='#08427B'). Ni themeCSS ni clases CSS los tocan.

▸ enfoque

Migrar todo diagrama C4 de sintaxis C4Context a flowchart TD + classDef. classDef da control total sobre fill, stroke y color por nodo, manteniendo los mismos primitivos visuales (persona, boundary, container).

src/components/MermaidViewer.astro javascript
// Antes: C4Context (pinta con fills inline)
C4Context
  Person(user, "Visitor")
  System(sys, "automata.pe")

// Despues: flowchart + classDef (themeable)
flowchart TD
  user(((Visitor)))
  sys["automata.pe"]
  user --> sys

  classDef person fill:#0D1117,stroke:#4ADE80,color:#E5E7EB
  classDef system fill:#0D1117,stroke:#06B6D4,color:#E5E7EB
  class user person
  class sys system
// section 07 · testing & ci

$ cat ./testing.md

▸ estrategia

Typecheck en cada PR (astro check). Playwright smoke test para el flujo critico (Cmd+K → elegir proyecto → carousel + lightbox funcionan). Lighthouse CI corre pero soft-fail. El script de auditoria i18n asserta que EN + ES tienen los mismos proyectos con los mismos field sets.

▸ herramientas
astro check (TypeScript)PlaywrightLighthouse CItools/i18n-audit.mjs
// section 09 · resultados

$ cat ./resultados.md

01 /
168
commits (y subiendo)
02 /
12+
componentes reusables (MasterDetail, Carousel, MermaidViewer, CommandPalette, Lightbox, ...)
03 /
0 KB
JS al cliente en pages sin interactividad
04 /
9
case studies, todos desde un solo translations.ts
▸ outcomes

El sitio es pitch, portfolio y sandbox a la vez. Cada componente (MasterDetail, Carousel, MermaidViewer, CommandPalette, Lightbox) es reusable en otros proyectos. Agregar un case study es un objeto tipado, en EN y ES, auditado por un script.

// section 10 · lecciones

$ cat ./lessons.md

// si lo hiciera de nuevo

  • 01 /

    Empezar por la estetica condiciono toda la API del codigo

    El primer commit fue 'paleta + JetBrains Mono'. Esa decision se propago a nombres de variables CSS (--green, --line), a nombres de botones (btn-cli), al estilo de hovers (border-color en vez de shadow), incluso al naming de secciones (// section 03). Lo que parecia branding termino siendo la arquitectura.

  • 02 /

    Server-side highlights > libraries client-side

    Shiki en build time genera HTML estatico — cero JS al cliente. Mermaid no se puede precompilar (es interactivo) asi que lazy-load via CDN. Regla: si no necesita interactividad en runtime, hacelo server-side.

  • 03 /

    Pair-programming con LLM cambio el ratio explorar/construir

    Probar cuatro layouts (stacked → carousel → tabs → master-detail) tomo lo que tomaria probar uno solo a mano. Consecuencia inesperada: requerir commits granulares se volvio disciplina, sino auditar que termino aprobado se vuelve imposible.

// siguiente paso

$ automata deploy --tu-operacion

// Conversemos sobre como adaptamos esto a tu caso.

./contactar.sh