Use Cases (Actualizado: 2/6/2026)

Cómo crear un portfolio con Claude Code y Astro: implementación y revisión

Crea un portfolio con Claude Code y Astro: código copiable, SEO, casos de uso, errores frecuentes y checklist de publicación.

Cómo crear un portfolio con Claude Code y Astro: implementación y revisión

Empieza por la decisión que debe facilitar tu portfolio

Un portfolio no es solo una galería de capturas. Es una página de decisión para reclutadores, clientes pequeños, organizadores de charlas o personas que quieren colaborar contigo. En pocos minutos deberían entender qué haces, qué problemas has resuelto, qué pruebas puedes enseñar y cómo contactarte.

En esta guía usaremos Claude Code como compañero de desarrollo local. Según la documentación oficial de Claude Code, puede leer el código, editar archivos, ejecutar comandos y trabajar con tus herramientas de desarrollo. Eso lo hace útil para construir una primera versión, revisarla y ejecutar comprobaciones sin perder de vista los cambios.

La implementación usa Astro y CSS simple. Para un portfolio personal, muchas páginas pueden generarse como HTML estático: cargan rápido, son fáciles de alojar y no obligan a añadir React o una librería pesada antes de necesitarla. La estructura oficial de Astro project structure también es clara para trabajar con Claude Code.

Si aún estás empezando, lee antes la guía interna de primeros pasos con Claude Code. Para profundizar en este stack, combina este artículo con desarrollo Astro con Claude Code.

Alcance de la primera versión

Vamos a crear una sola página con Hero, About, Projects, Services y Contact. No añadiremos CMS, base de datos ni formulario con backend en la primera ronda. El objetivo es publicar algo claro, revisable y fácil de mejorar.

flowchart TD
  A["Brief del portfolio"] --> B["src/data/profile.ts"]
  B --> C["src/pages/index.astro"]
  C --> D["src/styles/global.css"]
  D --> E["npm run build"]
  E --> F["Revisión antes de publicar"]

La idea clave es separar contenido y presentación. src/data/profile.ts guarda perfil y proyectos; index.astro se concentra en mostrar la página. Cuando más tarde pidas a Claude Code “mejora solo el copy de los proyectos” o “cambia el layout de tarjetas”, el cambio será pequeño y fácil de revisar.

my-portfolio/
  src/
    data/profile.ts
    pages/index.astro
    styles/global.css
  public/
    ogp.png
    projects/booking-site.webp

Las imágenes en public/ se sirven como /projects/booking-site.webp. La referencia de MDN para img recuerda que el texto alt debe describir el contenido. Para imágenes debajo del primer viewport, la guía de lazy loading explica el atributo loading="lazy".

Prompt práctico para Claude Code

Un prompt vago produce una web vaga. En vez de pedir “hazme un portfolio bonito”, define audiencia, archivos, restricciones y criterio de terminado.

Quiero construir un portfolio personal con Astro.
La audiencia son reclutadores y clientes pequeños que deben entender mi trabajo en menos de tres minutos.

Requisitos:
- Una página con Hero, About, Projects, Services y Contact
- Guardar perfil y proyectos en src/data/profile.ts
- Implementar src/pages/index.astro y src/styles/global.css
- No añadir React ni una librería pesada de UI
- Todas las imágenes deben tener alt
- Los botones CTA deben verse bien en móvil
- Terminar ejecutando npm run build

Antes de editar, resume el plan de implementación y los archivos que vas a tocar.

Pedir el plan antes de editar te permite detectar desvíos de alcance. Si Claude Code quiere instalar animaciones, crear un API route o añadir un CMS, puedes preguntar por qué antes de aceptar. Para la revisión posterior, usa la guía de SEO con Claude Code.

Código base copiable

Si partes de cero, crea el proyecto. Si ya tienes repositorio, pide a Claude Code que inspeccione la estructura actual y adapta los archivos.

npm create astro@latest my-portfolio
cd my-portfolio
npm run dev

Después crea el archivo de datos. Los proyectos deben contar una historia concreta: problema, rol, implementación y resultado. Una lista de tecnologías sin contexto rara vez convence.

// src/data/profile.ts
export const profile = {
  name: "Masa Tanaka",
  role: "Frontend engineer / consultor de adopción de Claude Code",
  location: "Tokyo, Japan",
  summary:
    "Construyo sitios rápidos y mantenibles con Astro, React, TypeScript y operaciones de contenido orientadas a resultados medibles.",
  skills: ["Astro", "TypeScript", "React", "CSS", "SEO", "Content Ops"],
  links: {
    email: "masa@example.com",
    github: "https://github.com/example",
  },
} as const;

export const projects = [
  {
    title: "Mejora del flujo de reservas",
    description:
      "Reorganicé menú móvil, explicación de servicios y CTA de reserva para reducir la fricción antes del contacto.",
    image: "/projects/booking-site.webp",
    alt: "Captura de un sitio de reservas con tarjetas de servicio y botón principal",
    tags: ["Astro", "SEO", "Responsive"],
    url: "https://example.com/booking",
  },
  {
    title: "Dashboard SaaS de tareas",
    description:
      "Rediseñé tarjetas, filtros de estado y pantallas vacías para que usuarios nuevos entendieran el flujo.",
    image: "/projects/task-dashboard.webp",
    alt: "Captura de un dashboard SaaS con tarjetas de tareas y filtros",
    tags: ["TypeScript", "UI Design", "Dashboard"],
    url: "https://example.com/dashboard",
  },
] as const;

La página puede empezar así. El contacto usa mailto: porque una primera versión no necesita backend.

---
import { profile, projects } from "../data/profile";
import "../styles/global.css";
---

<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>{profile.name} | Portfolio</title>
    <meta name="description" content={`${profile.role}: proyectos seleccionados, servicios y contacto.`} />
    <meta property="og:title" content={`${profile.name} | Portfolio`} />
    <meta property="og:description" content={profile.summary} />
    <meta property="og:image" content="/ogp.png" />
  </head>
  <body>
    <main>
      <section class="hero" aria-labelledby="hero-title">
        <p class="eyebrow">{profile.location}</p>
        <h1 id="hero-title">{profile.name}</h1>
        <p class="lead">{profile.summary}</p>
        <div class="actions">
          <a class="button primary" href="#projects">Ver proyectos</a>
          <a class="button secondary" href={`mailto:${profile.links.email}`}>Empezar conversación</a>
        </div>
      </section>

      <section id="projects" class="section" aria-labelledby="projects-title">
        <h2 id="projects-title">Projects</h2>
        <div class="project-grid">
          {projects.map((project) => (
            <article class="project-card">
              <img src={project.image} alt={project.alt} width="960" height="540" loading="lazy" />
              <div class="project-body">
                <h3>{project.title}</h3>
                <p>{project.description}</p>
                <ul class="tag-list">
                  {project.tags.map((tag) => <li>{tag}</li>)}
                </ul>
                <a href={project.url} target="_blank" rel="noreferrer">Leer más</a>
              </div>
            </article>
          ))}
        </div>
      </section>
    </main>
  </body>
</html>

Y este CSS cubre la base: ancho estable, botones accesibles y grid responsive.

/* src/styles/global.css */
:root {
  --bg: #f7f3ec;
  --panel: #ffffff;
  --text: #1f2933;
  --muted: #5f6c7b;
  --accent: #0f766e;
  --line: #d8dee4;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: Inter, system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.75;
}

.hero,
.section {
  width: min(1120px, calc(100% - 32px));
  margin: 0 auto;
}

.hero {
  min-height: 82vh;
  display: grid;
  align-content: center;
}

.actions,
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: 0;
  list-style: none;
}

.button {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  padding: 0 18px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  text-decoration: none;
  font-weight: 700;
}

.button.primary {
  background: var(--accent);
  color: white;
}

.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 24px;
}

.project-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}

.project-card img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

@media (max-width: 640px) {
  .button {
    width: 100%;
  }
}

Casos de uso reales

Un portfolio cambia según el lector. Pide a Claude Code que revise el sitio contra un escenario concreto.

Caso de usoQué quiere validar el lectorQué debe mostrar la página
Búsqueda de empleoRango técnico, responsabilidad, evidenciaStack, rol, tamaño de equipo, demo o GitHub
FreelanceEncaje con un problema de negocioServicios, ejemplos, CTA de email, entregables
Charlas o escrituraAutoridad temática y biografíaTemas, artículos, foto, bio corta
Aprendizaje públicoProgreso y reproducibilidadDiario, errores, demo, próximos pasos

Para empleo, escribe tu responsabilidad real en cada proyecto. Para freelance, crea entradas de conversación: auditoría de landing, revisión de velocidad, mejora de CTA, revisión de flujo con Claude Code. Para charlas, el hero debe mostrar el tema principal y enlazar a artículos o presentaciones.

ClaudeCodeLab usa esta lógica para monetización: contenido gratuito para crear confianza, recursos descargables para dar el primer paso y consultoría para problemas concretos. Un CTA útil no dice solo “contacta”; explica qué tipo de conversación tiene sentido. Puedes tomar como referencia la página de training y consultoría.

SEO, accesibilidad y errores frecuentes

SEO en un portfolio significa claridad. Usa palabras que tu audiencia sí buscaría: “portfolio frontend”, “desarrollador Astro”, “consultoría Claude Code”, o una palabra local si vendes servicios en una ciudad. Inclúyelas en título, description, h1 y proyectos de forma natural.

Revisa este portfolio Astro desde SEO y accesibilidad.
Comprueba title, description, jerarquía h1/h2/h3, alt de imágenes, enlaces internos,
enlaces externos, CTA y legibilidad móvil.
Devuelve solo problemas, razones y la corrección mínima.

Los errores comunes son claros. Primero, sobreconstruir: animaciones y librerías antes de explicar quién eres. Segundo, pruebas vagas: “sé React” no dice qué problema resolviste. Tercero, publicar sin revisar enlaces, OGP, móvil y npm run build. Cuarto, pegar datos privados de clientes, URLs internas o valores de .env en una conversación con IA. Usa capturas anonimizadas o datos ficticios.

Resultado probado y siguiente paso

La parte más útil de este flujo es separar contenido en src/data/profile.ts. En la práctica, eso permite pedir cambios de copy sin mezclar layout, y cambios visuales sin tocar datos. La revisión de Claude Code se vuelve más corta y más fácil de aprobar.

Antes de publicar, ejecuta npm run build y revisa Hero, Projects y Contact en móvil. Después de publicar, mejora con datos reales: qué proyectos reciben clics, qué CTA genera conversaciones y qué explicación sigue causando preguntas. Un portfolio rentable se cuida como un producto pequeño, no como una página terminada para siempre.

#Claude Code #portfolio #Astro #CSS #SEO
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.