mi portafolio son 42 repositorios y no dice nada

dev · Oct 4, 2026 · 8 min read

el perfil de github detrás de este sitio tiene 42 repositorios públicos. es lo más completo que he hecho nunca y también es lo menos útil.

toda la autodescripción de esa cuenta son seis caracteres: 20x dev.

esta es la entrada que pondría primero, porque es la razón por la que existe todo lo demás.

qué son en realidad 42 repositorios

medí el perfil con la api de github en lugar de suponer, y aquí está todo:

qué cuántos
repositorios públicos 42
de esos, forks 15
sin descripción alguna 12
estrellas totales, los 42 juntos 14
forks totales 1
primer commit 2023-01-29
push más reciente 2026-09-22

y los lenguajes, que es donde el perfil deja de hablar de mí:

lenguaje repos
JavaScript 11
Java 9
Python 6
ninguno (sin git linguist) 5
CSS, Vue 2 cada uno
Rust, OCaml, PowerShell, Brainfuck, TypeScript, Svelte, HTML 1 cada uno

nueve repositorios en java. casi todos de minecraft: un cliente, un plugin, un complemento de recompensas, un aldeano en un balde, una versión pública replicada. esa es una parte real y honesta de mi historia — era un crío al que le gustaba construir cosas para un juego — pero no es un portafolio de diseño, y no es lo que hago ahora.

así que un visitante llega a este perfil y concluye una de dos cosas: o esta persona dejó de ser interesante alrededor de 2023, o esta persona nunca ha tenido una opinión sobre nada. las dos lecturas son falsas, y la página no les da forma de averiguarlo. eso no es un problema de formato. es un argumento que nunca se hizo.

por qué una lista no es un portafolio

una lista responde «qué existe». un portafolio tiene que responder «por qué».

42 filas de nombre · lenguaje · estrellas · descripción son una respuesta completa a la primera pregunta y nula a la segunda. la completitud no sustituye al argumento — si acaso lo esconde, porque 42 filas parecen evidencia y ninguna es un motivo.

el fallo concreto aquí es que una fila no puede contener una decisión. todas las filas tienen la misma forma, así que todas dicen lo mismo, y lo único que las distingue es un número que mide la atención de otra gente. ordena la página por estrellas y tienes cuatro proyectos y mucho espacio vacío. ordénala por pushed_at y tienes un registro de cambios.

lo que muestro de verdad: 9 de 42

este sitio muestra nueve. es el 21% del perfil, y la selección son nueve líneas de un script de compilación, no una consulta:

const FEATURED: { name: string; tags?: string[] }[] = [
  { name: "portfolio-finder" },
  { name: "dektop-cleaner" },
  { name: "terraria_mods_extractor" },
  { name: "4webvideo" },
  { name: "sorting-visualizer", tags: ["JavaScript", "React", "Visualization"] },
  { name: "wplace-theme-changer" },
  { name: "darkwplace-extension" },
  { name: "task-manager" },
  { name: "Frenxys" },
];

ese array es el portafolio. no la respuesta de la api, no la base de datos — nueve nombres en el orden en que quiero que se vean, con todo lo demás descargado y deliberadamente no mostrado.

el orden es la primera decisión de diseño y es con la que más luché. la api me da el perfil ordenado por updated, que es la respuesta correcta a «qué tocaste por última vez» y una respuesta inútil a «qué debería mirar». la descarga conserva mi orden y descarta el orden por defecto:

/** conserva el orden curado y avisa en voz alta si desaparece un repo destacado. */
function selectFeatured(repos: GhRepo[]) {
  for (const entry of FEATURED) {
    const repo = byName.get(entry.name.toLowerCase());
    if (!repo) { missing.push(entry.name); continue; }
    picked.push(repo);
  }

un proyecto de 2025 está junto a uno de 2026 porque ese es el argumento, no por una marca de tiempo. la actualidad no es un argumento.

la segunda decisión es más silenciosa: los nueve destacados suman 8 estrellas entre ellos, y cuatro tienen cero. si curara por estrellas la página estaría vacía. las estrellas son una propiedad de la atención ajena, no del trabajo.

cada proyecto, y la decisión que representa

esta es la parte que una lista no puede hacer. cada tarjeta de la cuadrícula de proyectos está aquí porque representa algo que decidí sobre cómo se comporta este sitio:

  • portfolio-finder (JavaScript, 3 estrellas) — una herramienta que encuentra los portafolios de otras personas. está aquí porque este sitio hace lo mismo en tiempo de compilación: descargar una vez, generar un archivo, y que nadie consulte github en ejecución. el respaldo es una lista codificada en constants.ts, y existe por la misma razón que existe aquella herramienta.
  • dektop-cleaner (JavaScript/electron, 2 estrellas) — está aquí para dejar claro lo de pushedAt: el campo se lleva al modelo de datos y nunca se usa para ordenar. una herramienta de 2025 se gana la misma tarjeta que una de 2026.
  • terraria_mods_extractor (PowerShell, 0 estrellas) — un único script de shell, y se lleva la misma tarjeta que una app en react. buildTags siempre pone el lenguaje primero, así que la insignia dice POWERSHELL en la misma posición con el mismo peso. la cuadrícula no ordena por prestigio, porque una cuadrícula que ordena por prestigio es una tabla de posiciones.
  • 4webvideo (Python, 0 estrellas) — está aquí por una decisión que no tomé: no hay filtro de idioma ni búsqueda sobre nueve elementos. ambos costarían más en código y en ruido visual de lo que devolverían.
  • sorting-visualizer (JavaScript/React) — el único proyecto con etiquetas escritas a mano, porque las entradas de FEATURED aceptan un tags propio. los metadatos automáticos son un valor por defecto, no una jaula: cuando la máquina no puede describir el trabajo, lo escribe la persona.
  • wplace-theme-changer y darkwplace-extension (JavaScript, 1 estrella cada uno) — ambos son el mismo problema que luego resolví para mí: repintar en tiempo de ejecución algo que no te pertenece, sin recargar. el tema de la extensión del navegador, el tema de la app. están junto al sistema de temas de este sitio por una razón, y esa razón es la única por la que están en la página.
  • task-manager (JavaScript) — su descripción en github es literalmente solo una url: https://taskmanager-enea.web.app/. por eso el tipo Project tiene un campo homepage en absoluto. la descripción debería apuntar a la cosa que funciona, y cuando no lo hace, el modelo tiene otro sitio donde ponerlo.
  • Frenxys (Brainfuck, 1 estrella) — un repositorio de broma: un readme, y el mismo readme escrito en brainfuck. está destacado porque la curación es editorial y un portafolio no tiene que ser uniformemente serio. si quitara todo lo no serio, también quitaría todo lo que hacía que la cuenta mereciera la pena mirar.

la parte que borré, que es lo más honesto de aquí

la lista curada tenía antes entradas escritas a mano para cuatro proyectos antiguos. las quité, y el comentario en constants.ts dice por qué:

las entradas escritas a mano anteriores (demarkify, torr, beetrap, sniffcli y compañía) se eliminaron: esos repositorios solo existen bajo la cuenta del propietario antiguo y dan 404 bajo Frenxys, así que mantenerlos significaba enviar enlaces muertos.

lo comprobé, y es cierto. las cuatro devuelven 404 bajo Frenxys y 200 bajo la cuenta antigua. así que mi portafolio curado estaba enviando enlaces a la nada.

eso es peor que no tener portafolio, porque parece curado. un enlace muerto en una lista elegida a mano es una mentira con un diseño alrededor: dice «elegí esto» apuntando a nada. prefiero nueve tarjetas vivas que quince muertas, y borré cuatro para que el número sea cierto.

lo que construir este sitio costó de verdad

porque una entrada así puede convertirse en autobombo, la factura. este sitio es una app react renderizada en cliente con:

  • 189 urls en el sitemap — 35 rutas, 7 de ellas navegación y 28 entradas, en los 7 y los 3 idiomas donde ese contenido existe de verdad — y un generador que falla la compilación si una entrada del código no tiene url en el sitemap, que es la única forma que encontré de parar las páginas huérfanas
  • una descarga de github en tiempo de compilación con respaldo, así que ningún visitante consulta github nunca
  • un service worker, recursos con hash, repintado del tema en ejecución, una versión terminal q/ctrl+c servida a curl
  • 28 entradas, y durante meses solo 8 estaban realmente publicadas — un helper with_placeholder_copy reescribía las otras 20 con lorem ipsum en ejecución, así que borradores terminados que llevaban medio año en el código se publicaban como texto de relleno
  • una puerta check:dist que nunca había fallado: ok() imprimía FAIL y luego se olvidaba de contarlo, así que 1.710 aserciones no surtían efecto

me gasté todo eso en el marco. nueve proyectos son visibles. esa proporción es el punto entero, y es el argumento a favor del marco: la lista nunca fue el problema, así que el esfuerzo puesto en la lista no compra nada.

por qué existe este sitio

un perfil de github es una afirmación sin argumento. este sitio es el argumento.

existe para que cada afirmación pueda ir seguida del código que la hace y, donde me equivoqué, de la entrada donde lo digo. ocho de estas entradas son reales y todas terminan con algo que hice mal — un sniffer que no detecta lo que su readme promete, un honeypot cuyo fallo de enlace es silencioso, un sitemap que dejó huérfanas 37 páginas, un tema publicado con sombras codificadas, un bug que arreglé con tres ediciones y nunca diagnostiqué, un respaldo que hubo que reescribir por un bot, y una auditoría de privacidad que encontró tres orígenes de terceros que no sabía que estaban ahí.

ese es el portafolio. no los 42 repositorios — la capacidad de mostrar el trabajo y luego negarse a tapar las costuras. una lista de enlaces no puede hacer eso. solo puede apuntar a un repositorio y esperar que no lo leas.

qué le diría a mi yo del pasado

  • la completitud no es un argumento. 42 no es mejor que 9. si no puedes decir por qué algo está en la lista, no has curado, has reflejado — y los 15 forks son la prueba de que sé lo que es reflejar.
  • borra antes de publicar enlaces muertos. una lista curada con una entrada rota es peor que ninguna lista curada, porque la curación es la afirmación y el enlace es la prueba.
  • la lista nunca fue el problema. seguía pensando que la solución era escribir mejores descripciones. la solución era tener algo que decir.