Construyendo un entrenador completo de Rubik's Cube en una sola sesion con IA

5 min de lectura

La idea

Queria un sitio que enseñe algoritmos de Rubik’s cube de forma interactiva. No videos, no imagenes estaticas, no notacion seca en una tabla. Animaciones 3D reales donde puedas ver cada movimiento, pausar, retroceder, y comparar variantes lado a lado.

El metodo CFOP tiene 119 casos distribuidos en tres etapas: F2L (41 casos), OLL (57 casos) y PLL (21 casos). Cada caso tiene entre 2 y 3 algoritmos alternativos. Son 240 algoritmos en total que necesitan estar correctos — un error en la notacion y el cubo no se resuelve.

La apuesta: construir todo el proyecto en una sola sesion con Claude Code, desde npm create astro hasta tener las 4 fases del roadmap completadas.

El stack

La decision de arquitectura mas importante fue usar Astro con islands architecture. Un sitio de algoritmos es mayormente contenido estatico — las grids de casos son HTML puro. Solo necesitas JavaScript para dos cosas: el visor 3D (cubing.js pesa ~1MB) y la interactividad de filtros/busqueda.

// El TwistyPlayer se carga SOLO en paginas de detalle
// En las grids no se carga ni un byte de cubing.js
<TwistyPlayer client:only="react" algorithm={alg.notation} setup={caseData.setup} />

El client:only="react" es clave. cubing.js usa APIs del browser que rompen SSR, asi que le decimos a Astro que ni intente renderizarlo del lado del servidor.

El stack completo:

  • Astro 6 — genera 124 paginas estaticas en ~1.8 segundos
  • React 19 — solo para islands interactivos
  • Tailwind CSS v4 — dark theme, responsive
  • TypeScript strict — sin any, interfaces tipadas para todo el modelo de datos
  • cubing.js — renderizado 3D y validacion de algoritmos

La validacion como safety net

Este es el feature mas critico y el menos visible. Antes de que cualquier algoritmo llegue al sitio, un script lo valida matematicamente:

scripts/validate-algorithms.ts
const kpuzzle = await cube3x3x3.kpuzzle();
const solvedState = kpuzzle.defaultPattern();
// Para cada algoritmo: aplicar setup, luego algoritmo, verificar resuelto
const scrambled = solvedState.applyAlg(new Alg(setup));
const result = scrambled.applyAlg(new Alg(notation));
const isValid = result.isIdentical(solvedState);

npm run validate corre esto contra los 240 algoritmos. Si alguno falla, el build se rompe. Esto me dio la confianza para generar datos agresivamente — si la matematica pasa, el algoritmo es correcto.

Resultado: 240/240 algoritmos validados en los tres stages.

4 fases en una sesion

El proyecto se organizo en un roadmap de 4 fases con 23 tareas. La ejecucion fue asi:

Phase 1 — Foundation (8 tareas): Setup del proyecto, integracion cubing.js, modelo de datos, 21 casos PLL con 44 algoritmos, script de validacion, grid y paginas de detalle.

Phase 2 — Full Algorithm Set (6 tareas): 57 casos OLL (114 algoritmos), 41 casos F2L (82 algoritmos), paginas para los tres stages, search/filter con grupos colapsables.

Phase 3 — Polish (5 tareas): Responsive mobile, navegacion prev/next, comparacion side-by-side de algoritmos, SEO (Open Graph, sitemap, JSON-LD), performance con chunk splitting.

Phase 4 — Growth (5 tareas): Practice mode con scrambles random y timer, progress tracking en localStorage, guia de contribucion, scaffolds para ads y donaciones.

25 commits. 124 paginas. Todo en una sesion.

Decisiones tecnicas interesantes

Chunk splitting manual

cubing.js es una libreria grande (~967KB). Sin configuracion, Vite la fragmenta en 17 chunks que se cargan de forma impredecible. Con manual chunks:

astro.config.mjs
vite: {
build: {
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules/cubing')) return 'cubing';
if (id.includes('node_modules/react')) return 'react-vendor';
},
},
},
},
}

Resultado: las paginas de grid cargan ~9KB de JS. Las de detalle cargan un unico chunk de cubing.js que el browser cachea.

Datos como JSON estatico

Nada de base de datos, ni CMS, ni API. Los 240 algoritmos viven en tres archivos JSON que Astro importa en build time:

// En cualquier pagina Astro
import pllData from '../data/pll.json';
import type { StageData } from '../data/types';
const data = pllData as StageData;

Esto hace que el build sea deterministico y rapido. Si un algoritmo esta mal, lo corregis en el JSON, corres npm run validate, y rebuilds.

Practice mode con timer de reconocimiento

El practice mode muestra un caso random con su scramble. El usuario aplica el scramble en un cubo fisico, intenta reconocer el caso, y hace click en “Reveal” para ver el algoritmo. El tiempo entre que aparece el caso y el click se mide como “recognition time”.

const pickRandomCase = useCallback(() => {
const cases = stages[stage];
const randomIndex = Math.floor(Math.random() * cases.length);
setCurrentCase(cases[randomIndex]);
setRevealed(false);
setStartTime(Date.now());
}, [stage, stages]);

Simple pero efectivo para practicar reconocimiento de patrones.

Lo que queda pendiente

El proyecto esta funcional pero hay trabajo manual pendiente:

  • Algoritmos alternativos: Muchos segundos algoritmos en OLL y F2L son copias del default. Necesitan alternativas reales curadas por un cubero.
  • Deploy: El build funciona, falta conectar a Vercel.
  • AdSense y donaciones: Los scaffolds estan listos, faltan las cuentas reales.
  • QA visual: Verificar que todo se vea bien en dispositivos reales.

De donde salen los algoritmos

Aca le paso la posta a Claude, que explique el como se hizo la parte de datos.


Lo que sigue lo escribo yo, Claude. Luis me pidio que sea transparente con esta parte.

Los 240 algoritmos los genere yo desde mis datos de entrenamiento. No se scrapeo ningun sitio en tiempo real. Los algoritmos CFOP son ampliamente documentados en la comunidad de speedcubing — algdb.net, jperm.net, SpeedSolving wiki, cubeskills.com — y esa informacion esta en mi training data. Me “se” los algoritmos estandar de PLL, OLL y F2L de la misma forma que me se la sintaxis de TypeScript.

El safety net real es la validacion matematica. Para cada uno de los 240 algoritmos, el script de cubing.js toma el estado resuelto del cubo, aplica el scramble, aplica el algoritmo, y verifica que el resultado sea identico al estado resuelto. Si la matematica pasa, el algoritmo resuelve el caso. Los 240 pasaron.

Pero hay limitaciones que vale la pena ser honesto sobre:

  • Los defaults son confiables. Son los estandar de la comunidad — Sune, Anti-Sune, T Perm, J Perm. Los conozco bien de mi training data.
  • Los alternativos son el punto debil. Para unos 51 casos de OLL y varios de F2L, el segundo algoritmo es una copia del default. No pude generar alternativas distintas que pasaran validacion. Estan marcados como placeholders.
  • Validacion matematica no es validacion de ergonomia. El script verifica que el algoritmo resuelve el caso, pero no verifica que sea comodo, que sea finger-trick friendly, o que sea el que la comunidad realmente prefiere ensenar.

Por eso el review humano sigue siendo necesario. La matematica garantiza que resuelven el cubo. Un cubero garantiza que son los correctos para ensenar.

Devuelvo la posta a Luis.


Takeaways

  1. La validacion automatizada es lo que habilita velocidad. Sin el script de validacion, cada algoritmo necesitaria revision manual. Con el script, podes generar datos agresivamente y confiar en la matematica.

  2. Astro islands son perfectos para sitios de contenido con interactividad puntual. 9KB de JS en las grids vs 967KB en los detalles — esa diferencia no la logras con un SPA.

  3. El modelo de datos bien tipado escala. Las mismas interfaces TypeScript se usan para validacion, rendering, filtrado y el practice mode. Un cambio en el tipo se propaga a todo.

  4. Static JSON > base de datos para datasets acotados. 240 algoritmos en 3 archivos JSON. Build time: 1.8 segundos. Sin server, sin cold starts, sin costos.

El repo esta listo para contribuciones. Si sos cubero y queres mejorar los algoritmos alternativos, el CONTRIBUTING.md tiene todo lo necesario para arrancar.