Craft & Arquitectura
Design System
Este portfolio funciona sobre un sistema de diseño construido desde cero. No es una guía de estilo generada automáticamente — es una serie de decisiones explícitas: qué abstrae un token, cuándo merece existir un componente y cómo escala el layout sin deuda técnica.
La tipografía (Google Sans) define una jerarquía de 3 niveles con pesos 400 y 700 — sin intermedios
que rompan la coherencia. Los radios usan escala semántica
(rounded-ds-sm →
rounded-ds-xl)
para que los componentes se "sientan" parte del mismo sistema sin coordinar valores a mano.
El color dark mode usa la clase dark en
<html>,
lo que permite overrides quirúrgicos sin duplicar reglas.
Disponible como referencia técnica para equipos y reclutadores que quieran ver cómo pienso en sistemas, no solo en pantallas.
Componentes UI
Los primitivos en src/components/ui/
centralizan bordes, radios y CTAs. Los bloques de proyecto viven en components/project/ y los de plugin en components/plugin/.
| Componente | Ruta | Uso |
|---|---|---|
| DsSurface | ui/DsSurface.astro | Secciones con borde y fondo: section, inset, compact |
| DsTableShell | ui/DsTableShell.astro | Envolver <table> con scroll y borde |
| DsButtonLink | ui/DsButtonLink.astro | CTA principal (primary) o compacto en tablas (compact) |
| DsBadge | ui/DsBadge.astro | Tags en ProjectCard y similares |
| ProjectCard | ProjectCard.astro | Grid de proyectos en home (imagen 1:1, cursor custom desktop) |
| CaseStudyBlock | project/CaseStudyBlock.astro | Primitivo de bloque narrativo. El patrón vigente en wizzapp.astro usa grid inline de 12 cols — ver sección Páginas de proyecto |
| CaseStudyBanner | project/CaseStudyBanner.astro | Banner 16:9 full-width en casos de estudio. Props: imageSrc?, mobileBleed, ratio, caption. Sin hover/lightbox |
| Carousel | Carousel.astro | Galería horizontal full-width. images: string[] — slides cuadrados 1:1. Arrastre con Pointer Events |
| PluginCarousel | PluginCarousel.astro | Carrusel de tarjetas de plugins en PortfolioHome (#plugins). Arrastre con translateX |
| PluginDocNav | plugin/PluginDocNav.astro | Sidebar sticky (desktop) + collapsible (mobile) para docs de plugins. Props: currentPath, navItems? (default: PLUGIN_CSG_NAV), toc?. Scroll spy integrado |
| ColorScaleLegalShell | plugin/ColorScaleLegalShell.astro | Shell de páginas legales de ScaleKit (Layout + PluginDocNav + prose) |
| CopykitLegalShell | plugin/CopykitLegalShell.astro | Shell equivalente para páginas legales de CopyKit. Mismo patrón, datos de PLUGIN_CK |
| Lightbox | Lightbox.astro | Modal global de imagen (<dialog> nativo). Activado con data-lightbox-src en cualquier elemento del DOM |
| PortfolioHome | PortfolioHome.astro | Home completo (PluginCarousel + banner desktop + ProjectCard grid). En / (SITE_LIVE) o /home |
| ComingSoonPage | ComingSoonPage.astro | Página Coming Soon pública. Redirige a Dribbble. Activa cuando SITE_LIVE = false |
| Footer | Footer.astro | Pie global (Dribbble, LinkedIn, enlace a Design System) |
| AnimatedLogo | AnimatedLogo.astro | Marca animada en nav |
Vivos — primitivos UI
DsSurface variant="section"
Contenido dentro de un bloque de sección (ej. Centro de Ayuda del plugin).
DsTableShell + tabla
| Col A | Col B |
|---|---|
| Ejemplo | Fila |
Vivos — ProjectCard (demo)
Cursor custom en desktop; hover scale sobre la imagen.
Tipografía
Stack: Google Sans → system-ui → sans-serif.
Cargada en Layout.astro; reglas base en global.css; variables en design-tokens.css.
Pesos disponibles: 400 (cuerpo) y 700 (títulos). No asumir 300/500/600.
| Rol | Implementación | Tamaño / interlineado | Peso |
|---|---|---|---|
| Cuerpo (default) | body, p, font-sans | 1rem (16px) · line-height 1.6 | 400 |
| H1 global | h1, .heading-1 | 3rem desktop · 2rem ≤768px · lh 1.1 · tracking -0.02em | 700 |
| H2 global | h2, .heading-2 | 2rem · 1.5rem ≤768px · lh 1.2 | 700 |
| H3 global | h3, .heading-3 | 1.5rem · lh 1.3 | 700 |
| Eyebrow (sección) | .ds-eyebrow | 0.75rem · uppercase · tracking 0.2em · text-gray-500 | 400 |
| Título de bloque | .ds-heading-section | clamp(1.5rem, 2.5vw, 1.875rem) · font-black · lh 1.2 | 700 |
| Cuerpo grande | .ds-body-lg | clamp(1.125rem, 1.25vw, 1.375rem) · leading-relaxed | 400 |
Muestra .ds-eyebrow
Título de sección (.ds-heading-section)
Cuerpo grande (.ds-body-lg) — párrafo introductorio en casos de estudio.
Texto secundario (text-sm text-gray-500)
Layout & anchuras
| Contenedor | Clase | Uso |
|---|---|---|
| Home / proyectos | max-w-screen-2xl mx-auto px-8 | 1536px máximo; ancho útil 1472px en 1536px viewport |
| Plugin docs / Design System | max-w-screen-2xl mx-auto px-8 | 1536px máximo; dos columnas (sidebar + article) |
| Artículos legales / guía | max-w-3xl mx-auto px-8 | 768px máximo; lectura cómoda para prose |
| Padding lateral estándar | px-8 | 32px a cada lado; constante en todos los contenedores |
Imágenes del home — covers de proyectos
Las tarjetas ProjectCard usan imagen cuadrada (1:1), recorte object-cover.
| Contexto | Tamaño mostrado | Export recomendado |
|---|---|---|
| Desktop (2 cols, ≥ md) | ~696 × 696px | 1200 × 1200px o 1400 × 1400px (retina) |
| Móvil (1 col) | ~326px en iPhone 390 | 1200 × 1200px (mismo archivo, se recorta) |
Imágenes del home — banner de plugin (PluginCarousel)
| Contexto | Tamaño mostrado | Export recomendado |
|---|---|---|
| Móvil | Cuadrado, ancho útil (~326–400px) | 800 × 800px mín; 1200 × 1200px cómodo |
| Desktop | 240 × 240px (w-60) | 480 × 480px @2x |
Páginas de proyecto
La referencia canónica es src/pages/projects/wizzapp.astro.
Para un proyecto nuevo: duplica ese archivo, actualiza wizzImages, blueprintSteps y el contenido de cada sección. Añade un ProjectCard en PortfolioHome.astro.
Grid 12 columnas — patrón de sección
Cada sección de contenido usa grid grid-cols-12.
El ritmo es siempre: texto → banner.
| Elemento | Clases (desktop) | Rol |
|---|---|---|
| Encabezado de sección | col-span-12 lg:col-span-10 | eyebrow + h2 (10 cols). Technical chip (lg:hidden) para el side-note en mobile |
| Cuerpo narrativo | col-span-12 lg:col-span-8 | Párrafos, listas, blockquotes. 8 cols = anchura de lectura cómoda |
| Side-note técnico | hidden lg:flex lg:col-start-10 lg:col-span-3 | Contexto técnico en margen derecho. Oculto en mobile (substituido por chip) |
| Banner / imagen | col-span-12 | CaseStudyBanner mobileBleed={true} — imagen 16:9 full-bleed en mobile, redondeada en desktop |
| Banner rotativo (2+ slides) | col-span-12 | Carousel inline con flechas + dots superpuestos. Sin auto-rotate. Arrastre libre |
| Métricas / tablas | col-span-12 | Grid interno 2–3 cols para KPIs; tablas con overflow-x-auto rounded-ds-xl |
Gestión de imágenes en wizzapp.astro
Las rutas de imagen se centralizan en el frontmatter como único punto de edición:
// Un solo archivo como objeto
const wizzImages = {
hero: '/images/wizzapp/cover.png',
banner01: '/images/wizzapp/asset_01.png',
banner02: null, // pendiente
}
// Array para carousel de 2+ imágenes
const banner03Slides = ['/images/wizzapp/asset_03_01.png', ...]
Flag SHOW_GALLERY controla la galería final. Ponerlo en true cuando los assets estén listos.
Portada (hero) — medidas de export
Uso CSS / proporción Export master Hero de proyecto h-[clamp(160px,32vw,320px)] · object-cover 1920 × 640px (~3:1; recorte automático) Banner 16:9 (CaseStudyBanner) aspect-ratio: 16/9 · full-width 1920 × 1080px
Caso de estudio — bloques y galería
El patrón vigente en wizzapp.astro usa grid inline de 12 columnas
(ver sección anterior). CaseStudyBlock existe como primitivo de
respaldo pero las páginas de proyecto nuevas siguen el patrón de grid directo.
Medidas de imagen y Carousel
| Componente | Formato | Tamaño / notas |
|---|---|---|
| CaseStudyBanner | 16:9 (default) o ratio custom | Full-width del contenedor (hasta 1536px). Export 1920 × 1080px |
| Carousel (galería) | Cuadrado 1:1 por slide | images: string[]. Ancho slide ≈ min(85vw, 28rem). Export 1200 × 1200px |
| Banner carousel (b03-style) | 16:9 | Flechas + dots superpuestos. Drag libre. Sin auto-rotate. Export 1920 × 1080px por slide |
Service Blueprint — patrón de diagrama
Para visualizar flujos de servicio (ej. Wizz Life sección 02), se usa un grid inline de 4 columnas con "Línea de Visibilidad" interior. Datos en el frontmatter como array:
const blueprintSteps = [
{ num: "01", title: "Onboarding", frontstage: "...", backstage: "...", kpi: "..." },
...
];
Documentación de plugins
Cada plugin tiene su propio módulo de rutas y nav en src/data/plugin-[nombre]-urls.ts.
Este módulo es la fuente única de verdad para sidebar, breadcrumbs y tabla del Centro de Ayuda.
Estructura de datos de un plugin
// src/data/plugin-[nombre]-urls.ts
export const PLUGIN_XX_BASE = '/plugins/nombre';
export const PLUGIN_XX = { docs, guia, terminos, ... } as const;
export const PLUGIN_XX_FIGMA_URL = 'https://...';
export const PLUGIN_XX_NAV = [
{ label: "Documentación", href: PLUGIN_XX.docs },
// más ítems...
] as const;
Layout de página de docs
Dos columnas: PluginDocNav + article.
El componente acepta navItems para reutilizarse en cualquier plugin
sin duplicar el componente.
| Prop | Tipo | Descripción |
|---|---|---|
| currentPath | string | Astro.url.pathname.replace(/\/$/, '') — marca el ítem activo |
| navItems? | readonly NavItem[] | Lista de documentos del sidebar. Default: PLUGIN_CSG_NAV |
| toc? | TocItem[] | TOC en-página con scroll spy. Solo para guías (h2 en el artículo) |
Plugins activos
| Plugin | Data file | Shell legal | Páginas |
|---|---|---|---|
| ScaleKit | plugin-color-scale-urls.ts | ColorScaleLegalShell | index, guia, terminos, privacidad, aviso-legal, cookies, como-activar |
| CopyKit | plugin-copykit-urls.ts | CopykitLegalShell | index, guia, terminos, privacidad, aviso-legal, cookies |
Tokens CSS
Core palette
Color scale
Core primitives
Radius scale
ds-sm
ds-md
ds-lg
ds-xl
Core primitives
Section spacing
Typography
Type tokens
| Token | Raw value | Usage |
|---|---|---|
| --ds-text-eyebrow | 0.75rem | .ds-eyebrow |
| --ds-text-body | 1rem | text-base |
| --ds-text-body-lg | clamp(1.125rem, 1.25vw, 1.375rem) | .ds-body-lg |
| --ds-text-subtitle | clamp(1.125rem, 1.5vw, 1.5rem) | Subtítulos de sección |
| --ds-text-title-section | clamp(1.5rem, 2.5vw, 1.875rem) | .ds-heading-section |
| --ds-text-title-page | clamp(2.5rem, 5vw, 4.5rem) | H1 marketing |
Architecture
Grid system
| Token | Value | Role |
|---|---|---|
| --ds-grid-columns-mobile | 4 | grid compacto móvil |
| --ds-grid-columns-tablet | 8 | layout editorial tablet |
| --ds-grid-columns-desktop | 12 | patrón principal |
| --ds-grid-gutter-sm | 1rem / 16px | gutter móvil |
| --ds-grid-gutter-md | 1.5rem / 24px | gutter tablet |
| --ds-grid-gutter-lg | 2rem / 32px | gutter desktop |
| --ds-grid-margin-inline | 2rem / 32px | margen lateral base |
Architecture
Breakpoints
| Token | REM | PX |
|---|---|---|
| --ds-breakpoint-sm | 40rem | 640px |
| --ds-breakpoint-md | 48rem | 768px |
| --ds-breakpoint-lg | 64rem | 1024px |
| --ds-breakpoint-xl | 80rem | 1280px |
| --ds-breakpoint-2xl | 96rem | 1536px |
Architecture
Container widths
| Token | REM / PX | Usage |
|---|---|---|
| --ds-container-reading | 48rem 768px | legales / prose |
| --ds-container-docs | 64rem 1024px | docs + sidebar |
| --ds-container-wide | 96rem 1536px | home / project pages |
Architecture
Elevation
--ds-shadow-0
0 0 0 0 rgb(0 0 0 / 0)--ds-shadow-1
0 1px 2px rgb(17 24 39 / 0.08)--ds-shadow-2
0 4px 12px rgb(17 24 39 / 0.12)--ds-shadow-3
0 12px 24px -8px rgb(17 24 39 / 0.18)--ds-shadow-4
0 24px 48px -16px rgb(17 24 39 / 0.24)Architecture
Backdrop blur
Architecture
Z-index
Architecture
Motion
Durations
Easings