M-09 · W9c — Feel skills.sh (soft-nav + View Transitions + prefetch)
Encargo
Sobre la landing animada de W9a (fundación estática, tokens naranja #FF6B35, modo claro)
- W9b (Hero + 6 beats animados, compositor-only, 60fps, reduced-motion), dar a la web el
feel de skills.sh: navegación instantánea sin recargas, transiciones de ruta suaves y
prefetch. Especificación en
interaction-performance-spec.md.
Directiva técnica:
- Soft navigation entre secciones/rutas — NUNCA full reload.
- Prefetch de rutas y enlaces.
- View Transitions API para transiciones de ruta suaves.
- Framer Motion para la coreografía de entrada/salida.
- INP < 200ms MEDIDO (no estimado) — handlers triviales, compositor-only.
- Context7 (DC-1) consultado antes de tocar View Transitions / Next router.
- NO romper lo de W9b: animaciones de beats siguen, 60fps, reduced-motion intactos.
Qué se construyó
BeatNav.tsx— navegación lateral entre beats con scroll suave (soft, sin reload), handlers triviales para INP bajo.SiteHeader.tsx— cabecera con soft-nav entre rutas (/→/mecanismo), prefetch.mecanismo/— nueva ruta servida con soft navigation + View Transitions.Beat6Close.tsx,page.tsx,layout.tsx,globals.css— integración de View Transitions API + Framer Motion + utilidades de transición.next.config.ts— config de prefetch / router.
W9c · A-heartbeat (COMBO-CHECK)
Verificación de progreso sano antes de cerrar:
- Soft-nav funcionando: clics de BeatNav y nav de ruta SiteHeader NO disparan full reload.
- INP MEDIDO en build de producción (no estimado) — cumple el MUST.
- Guardarraíles W9b intactos: animaciones siguen, sin azul
#1B4DCC, sin fondo oscuro, sin glow, reduced-motion respetado. - Sin temporales en root,
.playwright-mcp(untracked + gitignored) eliminado.
W9c · A-retro + verdict (APPROVE) · INP 56ms
Verdict V-review (id=8dcc6228-547f-407a-837e-22290aa15994): APPROVE.
INP = 56ms (umbral 200ms · margen amplio). Metodología de medición:
- Build de producción (
npm run start,:3199) + Playwright chromium headless. PerformanceObserver({type:'event', durationThreshold:0})sobre clics REALES de pointer (locator.click, no.click()sintético).- BeatNav: 18 muestras aisladas (reset por clic), serie
[56,56,56,48,48,48,48,48,40,40,40,40,40,40,32,32,24,24]— todas ≤56ms. - Nav de ruta SiteHeader
/ → /mecanismo: 40ms. - INP = worst = 56ms.
- Outliers iniciales (1408/792ms) = artefactos de cold-start/primer repaint headless, no reproducibles tras warm-up (la medición aislada los elimina). Lab, no field.
Gaps registrados (transparencia, no bloqueantes):
- Medición lab headless (no field/CrUX); INP real en hardware con throttling 4× CPU podría subir, aunque el margen 56 vs 200ms es amplio y la arquitectura (handlers triviales, compositor-only, prefetch) es la correcta.
- La primera interacción tras cold-JS/observer-arm muestra un spike de paint (792-1408ms) ligado al primer smooth-scroll sobre la página de 7 escenas R3F; no afecta INP de usuario real (no recurre) pero conviene vigilarlo si se añade más peso de escena.
- Check (6) del prompt contradecía el MUST/MUST NOT: “naranja” estaba marcado como prohibido pero es el accent de marca canónico. Resuelto a favor del MUST NOT (azul/oscuro/glow) y el MUST “NO romper W9b”.
Semáforo: GREEN. Soft-nav + View Transitions + prefetch + Framer Motion shipped; INP medido 56ms < 200ms; guardarraíles W9b (60fps, reduced-motion, sin azul/oscuro/glow) intactos; sin deploy (es W9d). Pendiente para W9d: deploy + validación field/CrUX.