Escenas para producción
Dejando de jugar, empezando a profesionalizar
Hacer un cubo que gira en un archivo HTML es fácil. Mantener una experiencia Three.js compleja dentro de un framework moderno como Astro, React o Vue requiere disciplina arquitectónica. Si construyes tu código a lo bruto en un solo archivo, tendrás Memory Leaks, ventiladores sonando fuerte y una web inmanejable.
El problema de la basura (Garbage Collection)
A diferencia de los elementos del DOM que desaparecen cuando cambias de página, WebGL es terco. Si instancias Geometrías y Materiales en la memoria de la tarjeta gráfica (VRAM) y cambias de ruta en tu web, esa memoria NO se libera automáticamente.
Si el usuario entra y sale de tu página 3D varias veces, llenará la VRAM y el navegador cerrará la pestaña por seguridad (el clásico "Aw, Snap!" en Chrome).
El arte del Dispose
Todo lo que tenga una geometría, un material, o un renderer, tiene un método llamado .dispose(). Cuando la página se destruye (o el componente se desmonta), es TU responsabilidad recorrer la escena y ejecutar dispose en cada cosa.
Organización con Clases
En producción, no metemos todo en un archivo script.js. Creamos una clase WebGLApp o usamos patrones de arquitectura (como react-three-fiber en React). Separamos responsabilidades: un archivo para la escena, otro para la luz, y otro para manejar el resize.
Consejo profesional
En Astro, las View Transitions hacen que la página nunca recargue realmente. Esto agrava el problema de los memory leaks. Usa el evento astro:before-swap para cancelar el requestAnimationFrame y hacer el dispose completo de la escena antes de que cambie la ruta.
El Cleanup Perfecto
let animationId;
function animate() {
animationId = requestAnimationFrame(animate);
renderer.render(scene, camera);
}
// Cuando el usuario sale de la página...
function cleanUp() {
// 1. Detener el bucle, la CPU descansa
cancelAnimationFrame(animationId);
// 2. Liberar eventos del navegador
window.removeEventListener('resize', handleResize);
// 3. Recorrer y destruir geometrías y materiales de la VRAM
scene.traverse((child) => {
if (child.isMesh) {
child.geometry.dispose();
// Los materiales pueden ser un array
if (Array.isArray(child.material)) {
child.material.forEach(mat => mat.dispose());
} else {
child.material.dispose();
}
}
});
// 4. Destruir el proyector
renderer.dispose();
} Una escena optimizada con cleanup completo. Navega fuera para ver el dispose en acción.
Errores comunes
Practica lo aprendido
Sé un profesional responsable.