Canvas, cámara y frameloop: cómo montar una escena R3F que se vea bien y no renderice de más

Aprende a configurar `Canvas`, `PerspectiveCamera`, FOV, clipping planes y `frameloop="demand"` con criterio de producción. La meta no es solo ver un objeto 3D, sino decidir cómo se encuadra, cuándo se renderiza y por qué esa decisión importa en UX y rendimiento.

En una escena 3D profesional, `Canvas` no es un detalle de arranque: es el límite entre tu árbol React y el renderer. Define resolución, DPR, eventos, contexto y política de render. Si lo configuras mal desde el principio, lo pagarás después en legibilidad, rendimiento y control.

La cámara tampoco es una propiedad más. En un hero de producto, la combinación entre `position`, `fov`, `near` y `far` decide si el objeto se ve estable, agresivo, elegante o deformado. Muchos problemas visuales que parecen de modelado son, en realidad, problemas de cámara.

A esto se suma una decisión muy de 2026: no todo tiene que renderizar continuamente. Si tu escena está quieta y solo cambia al interactuar, `frameloop="demand"` te permite dejar de malgastar frames en GPU y batería.

Esta lección te enseña a encuadrar y a renderizar con intención. Es un salto pequeño en código, pero enorme en criterio técnico.

  • En R3F, `Canvas` decide cómo entra Three.js en tu app React.
  • Dentro de `Canvas` se crea el renderer, se inyecta la escena, se resuelve la cámara por defecto y se habilita el sistema de eventos. Por eso conviene pensar `Canvas` como infraestructura y no como un simple contenedor visual.
  • Las decisiones de `dpr`, `shadows`, `gl`, `frameloop` o `eventSource` no son adornos. Afectan a la nitidez, al consumo de GPU y a la forma en que el usuario interactúa con la escena.
  • Una buena cámara hace legible el modelo antes de tocar animaciones o luces.
  • El `fov` controla cuánta apertura percibe la cámara. Un FOV alto dramatiza y deforma; uno bajo comprime y estabiliza. No hay un número mágico universal, pero sí zonas razonables según intención: producto limpio, hero expresivo o escena inmersiva.

Canvas no es un wrapper: es la frontera del renderer

En R3F, `Canvas` decide cómo entra Three.js en tu app React.

Dentro de `Canvas` se crea el renderer, se inyecta la escena, se resuelve la cámara por defecto y se habilita el sistema de eventos. Por eso conviene pensar `Canvas` como infraestructura y no como un simple contenedor visual.

Las decisiones de `dpr`, `shadows`, `gl`, `frameloop` o `eventSource` no son adornos. Afectan a la nitidez, al consumo de GPU y a la forma en que el usuario interactúa con la escena.

PerspectiveCamera: FOV, posición y clipping no se eligen al azar

Una buena cámara hace legible el modelo antes de tocar animaciones o luces.

El `fov` controla cuánta apertura percibe la cámara. Un FOV alto dramatiza y deforma; uno bajo comprime y estabiliza. No hay un número mágico universal, pero sí zonas razonables según intención: producto limpio, hero expresivo o escena inmersiva.

La posición define el encuadre real. La misma cámara con `z` demasiado cerca puede parecer nerviosa; demasiado lejos, indiferente. Además, `near` y `far` determinan qué entra en el frustum visible. Si los ajustas mal, aparecen cortes raros o pérdida de precisión.

  • Hero de producto: suele funcionar bien un FOV entre 35 y 50.
  • Escena inmersiva o dramática: el FOV puede abrirse, pero con control.
  • Usa `near` lo bastante pequeño para no recortar el modelo, pero no exageres.
  • No dejes `far` absurdamente alto si no lo necesitas: empeora precisión de profundidad.

Cuándo usar `frameloop="demand"` y cuándo no

No toda escena necesita un render loop permanente.

Si tienes una pieza que solo cambia al hacer hover, drag, resize o al cargar un asset, renderizar 60 veces por segundo es un desperdicio. En esos casos `frameloop="demand"` permite redibujar solo cuando algo cambia de verdad.

Eso no significa que el modo `always` sea malo. Si la escena lleva animación continua, físicas, partículas o un shader vivo, necesitas frames constantes. La clave no es ser dogmático; es elegir el loop que corresponde a la naturaleza de la escena.

Presets útiles de cámara para web de producto

Pensar en presets te ahorra improvisación y facilita storytelling.

En vez de mover la cámara al tuntún, conviene pensar en presets: un encuadre general para hero, otro más contenido para detalle y uno lateral para dramatismo. Después, la animación solo conecta esos puntos de vista con sentido.

Este enfoque facilita mucho la siguiente lección de scroll cinematográfico, porque deja la narrativa de cámara preparada como una serie de vistas con propósito.

Debug común: lo que suele fallar en esta fase

Aquí conviene detectar errores antes de culpar al modelo o al render.

Si el objeto parece cortado, revisa `near` y `far` antes de tocar luces. Si la escena se siente pesada en móvil, revisa `dpr` y el tipo de frameloop antes de añadir optimizaciones más complejas. Si todo se ve raro, prueba primero una cámara frontal limpia con una sola luz.

Otro fallo clásico es animar cámara y objeto a la vez sin haber fijado un encuadre base. Cuando todo se mueve simultáneamente, resulta difícil saber qué está mal. El orden correcto es: escena en reposo, cámara correcta, luego animación.

  • Modelo recortado: revisa clipping planes.
  • Lectura torpe: revisa FOV y distancia.
  • Consumo innecesario: revisa `frameloop`.
  • Caos visual: congela la escena y valida primero una vista base.
Animaciones 3D en la Web
03

Canvas, cámara y frameloop: cómo montar una escena R3F que se vea bien y no renderice de más

Aprende a configurar `Canvas`, `PerspectiveCamera`, FOV, clipping planes y `frameloop="demand"` con criterio de producción. La meta no es solo ver un objeto 3D, sino decidir cómo se encuadra, cuándo se renderiza y por qué esa decisión importa en UX y rendimiento.

Código del tema: Canvas · PerspectiveCamera · frameloop

📘 Teoría

Canvas no es un wrapper: es la frontera del renderer

En R3F, `Canvas` decide cómo entra Three.js en tu app React.

Dentro de `Canvas` se crea el renderer, se inyecta la escena, se resuelve la cámara por defecto y se habilita el sistema de eventos. Por eso conviene pensar `Canvas` como infraestructura y no como un simple contenedor visual.

Las decisiones de `dpr`, `shadows`, `gl`, `frameloop` o `eventSource` no son adornos. Afectan a la nitidez, al consumo de GPU y a la forma en que el usuario interactúa con la escena.

1

`dpr`

Controla cuánta resolución real dibuja el canvas. En móvil conviene limitarlo.

2

`shadows`

Activa el pipeline de sombras. Úsalo solo cuando tenga sentido visual.

3

`frameloop`

Decide si la escena renderiza siempre o solo cuando debe actualizarse.

4

`gl`

Permite afinar el renderer cuando necesitas más control técnico.

Base de Canvas con intención
<Canvas
  dpr={[1, 1.5]}
  shadows
  frameloop="demand"
  gl={{ antialias: true, alpha: true }}
>
  {/* escena */}
</Canvas>

PerspectiveCamera: FOV, posición y clipping no se eligen al azar

Una buena cámara hace legible el modelo antes de tocar animaciones o luces.

El `fov` controla cuánta apertura percibe la cámara. Un FOV alto dramatiza y deforma; uno bajo comprime y estabiliza. No hay un número mágico universal, pero sí zonas razonables según intención: producto limpio, hero expresivo o escena inmersiva.

La posición define el encuadre real. La misma cámara con `z` demasiado cerca puede parecer nerviosa; demasiado lejos, indiferente. Además, `near` y `far` determinan qué entra en el frustum visible. Si los ajustas mal, aparecen cortes raros o pérdida de precisión.

  • Hero de producto: suele funcionar bien un FOV entre 35 y 50.
  • Escena inmersiva o dramática: el FOV puede abrirse, pero con control.
  • Usa `near` lo bastante pequeño para no recortar el modelo, pero no exageres.
  • No dejes `far` absurdamente alto si no lo necesitas: empeora precisión de profundidad.

Cuándo usar `frameloop="demand"` y cuándo no

No toda escena necesita un render loop permanente.

Si tienes una pieza que solo cambia al hacer hover, drag, resize o al cargar un asset, renderizar 60 veces por segundo es un desperdicio. En esos casos `frameloop="demand"` permite redibujar solo cuando algo cambia de verdad.

Eso no significa que el modo `always` sea malo. Si la escena lleva animación continua, físicas, partículas o un shader vivo, necesitas frames constantes. La clave no es ser dogmático; es elegir el loop que corresponde a la naturaleza de la escena.

1

Usa `always`

Cuando hay movimiento continuo, timeline constante, físicas o uniforms vivos por frame.

2

Usa `demand`

Cuando la escena está quieta y solo cambia por interacción o por cambios de estado puntuales.

3

`invalidate()`

Es la forma de pedir un nuevo frame cuando trabajas en modo bajo demanda.

4

Error típico

Dejar `always` por defecto aunque el objeto esté totalmente quieto.

Patrón básico con `invalidate()`
function Product() {
  const mesh = useRef();
  const { invalidate } = useThree();

  const onPointerEnter = () => {
    gsap.to(mesh.current.rotation, {
      y: mesh.current.rotation.y + Math.PI / 6,
      duration: 0.4,
      ease: "power2.out",
      onUpdate: invalidate
    });
  };

  return <mesh ref={mesh} onPointerEnter={onPointerEnter} />;
}

Presets útiles de cámara para web de producto

Pensar en presets te ahorra improvisación y facilita storytelling.

En vez de mover la cámara al tuntún, conviene pensar en presets: un encuadre general para hero, otro más contenido para detalle y uno lateral para dramatismo. Después, la animación solo conecta esos puntos de vista con sentido.

Este enfoque facilita mucho la siguiente lección de scroll cinematográfico, porque deja la narrativa de cámara preparada como una serie de vistas con propósito.

1

Hero

Plano amplio pero estable. Suele priorizar claridad y presencia de marca.

2

Detalle

Reduce distancia o ajusta foco para remarcar textura, material o un gesto del producto.

3

Lateral

Introduce más volumen y dramatismo, útil para transiciones o secciones intermedias.

4

Cenital técnico

Sirve para explicar despiece, capas o layout de componentes.

Debug común: lo que suele fallar en esta fase

Aquí conviene detectar errores antes de culpar al modelo o al render.

Si el objeto parece cortado, revisa `near` y `far` antes de tocar luces. Si la escena se siente pesada en móvil, revisa `dpr` y el tipo de frameloop antes de añadir optimizaciones más complejas. Si todo se ve raro, prueba primero una cámara frontal limpia con una sola luz.

Otro fallo clásico es animar cámara y objeto a la vez sin haber fijado un encuadre base. Cuando todo se mueve simultáneamente, resulta difícil saber qué está mal. El orden correcto es: escena en reposo, cámara correcta, luego animación.

  • Modelo recortado: revisa clipping planes.
  • Lectura torpe: revisa FOV y distancia.
  • Consumo innecesario: revisa `frameloop`.
  • Caos visual: congela la escena y valida primero una vista base.

🧭 Visuales clave

Relación entre Canvas, cámara y política de render

Ayuda a entender qué piezas decide `Canvas`, cómo la cámara define la lectura y cuándo conviene renderizar siempre o solo al invalidar.

Diagrama de React Three Fiber mostrando Canvas, PerspectiveCamera, frustum y la diferencia entre render continuo y render bajo demanda

🧪 Aprende probando

Ejemplo Demo guiada: render continuo frente a render bajo demanda Aquí no importa el motor real, sino la idea de producción. Cambia entre `always` y `demand`, mueve los controles y observa cómo cambia el contador de renders y la sensación de escena activa.
Ejemplo Ejemplo resuelto: escena de producto con cámara y render bajo demanda Este bloque ya sí está en React Three Fiber. No busca ejecutarse aquí, sino mostrar el patrón correcto para producción: una cámara clara y `invalidate()` cuando la escena no necesita animación continua.
Ejemplo Demo interactiva: escena orbital con Three.js y GSAP Cambia entre geometrías 3D y observa cómo GSAP coordina salida, entrada elástica y giro continuo de una malla dentro de una escena Three.js.

🏁 Retos

Reto Reto 1: configura una cámara de hero estable y un Canvas sensato Tu tarea es dejar una base de escena lista para producto: `Canvas` con render bajo demanda y una `PerspectiveCamera` con valores más razonables que un encuadre improvisado.

¿Qué es esto?

Soy Cristian Eslava y a veces hago webs para procrastinar yo y vosotros 😉.

Esta la hice en febrero de 2026 para facilitar el aprendizaje de mis alumnxs. Aprender desarrollo web practicando. La idea es que crezca semanalmente con nuevos temas, tests y retos.

Inspirado en MDN, en W3Schools, en Codepen, en el crack de Manz y en mil sitios de documentación sobre desarrollo web. Quería aportar además de bloques teóricos con ejemplos, la gamificación de los retos y el sistema de test que ya tenía en culTest .

Si te gustó, si no te gustó, si quieres saludarme, o invitarme a 🍻 no dudes en escribirme en cristianeslava@gmail.com .