Las interfaces de los sistemas y el sitio de Naoro comparten base: Next.js 16, React 19, TypeScript y CSS propio. El sitio agrega movimiento con GSAP y Lenis, y dibujo con Canvas y SVG.
App Router. Cada carpeta en app/ es una ruta. page.tsx es la página y layout.tsx envuelve a sus hijas.
Componentes de servidor por defecto. Solo lo que usa estado, efectos o el navegador lleva 'use client'. Esta guía es casi toda de servidor.
params es una promesa. En layouts y páginas dinámicas se lee con await. Los tipos LayoutProps y PageProps se generan solos y están disponibles sin importarlos.
Exportación estática. El sitio usa output: 'export': el build genera HTML en out/ y nginx lo sirve tal cual. No hay servidor de Node en producción, así que no hay rutas de API ni rutas dinámicas sin generateStaticParams.
Páginas solo de desarrollo. Los archivos page.dev.tsx existen solo con next dev (ver next.config.ts). Sirven para herramientas internas.
Fuentes con next/font: Host Grotesk desde Google y Departure Mono local, expuestas como variables CSS.
StrictMode está activo (reactStrictMode: true). En desarrollo cada efecto se monta, se limpia y se vuelve a montar. Por eso todo efecto de animación devuelve su limpieza y revisa si sigue vivo antes de arrancar.
Menos efectos. Si algo se puede calcular durante el render, no va en un useEffect.
Refs para todo lo que se anima o se mide. React pinta la estructura, GSAP y Canvas mueven los píxeles.
TypeScript estricto. Tipos explícitos en los datos de los motores (lib/demos/*.ts). El build falla si tsc falla.
Todo entra por lib/gsap.ts: registra los plugins una vez y exporta gsap, useGSAP, ScrollTrigger, SplitText y prefersReducedMotion. Nunca importes gsap directo en un componente.
Curvas propias: n.out para entradas largas y precisas, n.inOut para cambios de estado. Sin rebotes.
Las entradas de titulares están en lib/reveals.ts (revealArrive, revealBlocks, revealType…), con el hook useReveal. Reutilízalas antes de inventar otra.
Toda animación revisa prefersReducedMotion() primero y deja el estado final visible.
components/SmoothScroll.tsx crea Lenis y lo conecta con el reloj de GSAP para que ScrollTrigger lea la misma posición. lib/scroll.ts guarda la instancia y expone scrollToTarget y onSiteEnter. La barra de desplazamiento es propia (ScrollBar.tsx).
Canvas 2D + requestAnimationFrame para animaciones densas de celdas: el buscaminas del hero (lib/field.ts), la firma Partida del logo (lib/partida.ts), PixelMark y los planos de Capacidades. Con cientos de celdas, SVG con una animación por elemento se traba. Mide en Chrome real, no en suposiciones.
SVG en línea para ilustraciones con trazo: capas isométricas, glifos del proceso, antes y después. Algunos detalles usan la Web Animations API (element.animate).
IntersectionObserver pausa los canvas fuera de pantalla. ResizeObserver recalcula medidas y refresca ScrollTrigger cuando cambia la altura.
Solo en demos: Three.js en la demo de natación (/deporte) y Mapbox GL en el mapa de zonas. No se cargan en el home.