Volver a la guía

Paso 2: Implementación Básica

Aprende a integrar Spline en tus componentes React de manera efectiva

Nota: Esta página usa 'use client' para habilitar la interactividad de los botones de copiar código.

Implementación Básica

Integra una escena de Spline en tu componente React

import Spline from '@splinetool/react-spline/next';
export default function MiComponente() {
return (
<div className="w-full h-screen">
<Spline scene="/mi-escena.splinecode" />
</div>
);
}

Con Controles de Carga

Maneja el estado de carga y errores

import Spline from '@splinetool/react-spline/next';
import { useState } from 'react';
export default function SplineConControles() {
const [isLoading, setIsLoading] = useState(true);
const [hasError, setHasError] = useState(false);
const handleLoad = () => {
setIsLoading(false);
};
const handleError = () => {
setHasError(true);
setIsLoading(false);
};
return (
<div className="relative w-full h-screen">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-100 dark:bg-gray-800">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-pink-500"></div>
</div>
)}
{hasError && (
<div className="absolute inset-0 flex items-center justify-center bg-red-50 dark:bg-red-900/20">
<p className="text-red-600 dark:text-red-400">Error al cargar la escena</p>
</div>
)}
<Spline
scene="/mi-escena.splinecode"
onLoad={handleLoad}
onError={handleError}
/>
</div>
);
}

Como Fondo de Página

Usa Spline como fondo con contenido superpuesto

import Spline from '@splinetool/react-spline/next';
export default function PaginaConFondo() {
return (
<div className="relative min-h-screen">
{/* Fondo con Spline */}
<div className="fixed inset-0 z-0">
<Spline scene="/fondo-3d.splinecode" />
</div>
{/* Contenido superpuesto */}
<div className="relative z-10 flex min-h-screen items-center justify-center">
<div className="bg-white/80 dark:bg-black/80 backdrop-blur-sm rounded-2xl p-8 max-w-2xl">
<h1 className="text-4xl font-bold mb-4">Mi Contenido</h1>
<p className="text-lg text-gray-600 dark:text-gray-300">
Este contenido se superpone sobre la escena 3D de fondo
</p>
</div>
</div>
</div>
);
}

Landing Page Interactiva - WebCode

Landing page completa con escena de teclado interactiva en el lado derecho, permitiendo la interacción del usuario con el 3D mientras mantiene el contenido accesible en el lado izquierdo

Ver Demo Funcional
import SplineBackground from "@/components/SplineBackground";
import { SPLINE_SCENES } from "@/lib/spline-paths";
import { ArrowRight } from "lucide-react";
export default function LandingWebCode() {
return (
<div className="relative min-h-screen overflow-hidden">
{/* Escena Spline de fondo */}
<SplineBackground
scene={SPLINE_SCENES.KEYBOARD}
preset="BACKGROUND_RESPONSIVE"
className="fixed inset-0 z-0"
/>
{/* Zona interactiva - Lado derecho */}
<div className="fixed right-0 top-0 bottom-0 w-full md:w-1/2 z-5 pointer-events-auto" />
{/* Overlay para mejor contraste del texto - Lado izquierdo */}
<div className="fixed left-0 top-0 bottom-0 w-full md:w-1/2 bg-linear-to-r from-black/60 via-black/40 to-transparent z-1" />
{/* Contenido principal */}
<div className="relative z-10 min-h-screen flex items-center">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Hero Section - Lado izquierdo */}
<div className="space-y-8 pointer-events-auto">
{/* Badge */}
<div className="inline-flex items-center gap-2 bg-linear-to-r from-pink-500/10 to-cyan-500/10 backdrop-blur-sm border border-pink-500/20 rounded-full px-4 py-2">
<span className="text-sm font-medium bg-linear-to-r from-pink-400 to-cyan-400 bg-clip-text text-transparent">
✨ Nuevo diseño disponible
</span>
</div>
{/* Título principal */}
<div className="space-y-4">
<h1 className="text-5xl md:text-7xl font-bold">
<span className="bg-linear-to-r from-pink-400 via-purple-400 to-cyan-400 bg-clip-text text-transparent">
WebCode
</span>
</h1>
<p className="text-2xl md:text-3xl font-semibold text-white/90">
WebDesign
</p>
<p className="text-lg text-gray-300 max-w-lg">
Crea experiencias web únicas con diseño 3D interactivo.
Combina código elegante con visualizaciones impresionantes.
</p>
</div>
{/* CTAs */}
<div className="flex flex-col sm:flex-row gap-4">
<button className="group px-8 py-4 bg-linear-to-r from-pink-500 to-cyan-500 hover:from-pink-600 hover:to-cyan-600 text-white font-semibold rounded-xl transition-all duration-300 shadow-lg hover:shadow-pink-500/50 flex items-center justify-center gap-2">
Comenzar ahora
<ArrowRight className="w-5 h-5 group-hover:translate-x-1 transition-transform" />
</button>
<button className="px-8 py-4 bg-white/10 hover:bg-white/20 backdrop-blur-sm text-white font-semibold rounded-xl border border-white/20 transition-all duration-300">
Ver ejemplos
</button>
</div>
{/* Stats */}
<div className="grid grid-cols-3 gap-8 pt-8 border-t border-white/10">
<div>
<div className="text-3xl font-bold bg-linear-to-r from-pink-400 to-purple-400 bg-clip-text text-transparent">
100%
</div>
<div className="text-sm text-gray-400">Responsive</div>
</div>
<div>
<div className="text-3xl font-bold bg-linear-to-r from-purple-400 to-cyan-400 bg-clip-text text-transparent">
3D
</div>
<div className="text-sm text-gray-400">Interactivo</div>
</div>
<div>
<div className="text-3xl font-bold bg-linear-to-r from-cyan-400 to-pink-400 bg-clip-text text-transparent">
Fast
</div>
<div className="text-sm text-gray-400">Optimizado</div>
</div>
</div>
</div>
{/* Lado derecho - Espacio para interacción con la escena */}
<div className="hidden lg:block" />
</div>
</div>
</div>
</div>
);
}

Propiedades del Componente Spline

PropiedadTipoDescripción
scenestringURL o ruta del archivo .splinecode
onLoadfunctionCallback ejecutado cuando la escena se carga
onErrorfunctionCallback ejecutado si hay un error
styleobjectEstilos CSS personalizados
classNamestringClases CSS adicionales

Server Components vs Client Components

¿Cuándo usar 'use client'?

En Next.js 16, los componentes son Server Components por defecto. Añade 'use client' cuando necesites:

  • • Manejar eventos (onClick, onChange)
  • • Usar hooks de React (useState, useEffect)
  • • Acceder a APIs del navegador (window, document)
  • • Usar componentes de terceros que requieren JavaScript

Ejemplo de uso

'use client';
import { useState } from 'react';
import Spline from '@splinetool/react-spline/next';
export default function InteractiveSpline() {
const [isLoaded, setIsLoaded] = useState(false);
return (
<div>
{!isLoaded && <div>Cargando...</div>}
<Spline
scene="/escena.splinecode"
onLoad={() => setIsLoaded(true)}
/>
</div>
);
}

Landing Pages con Escenas Interactivas

Crear landing pages con escenas 3D interactivas requiere una arquitectura de capas cuidadosa para garantizar que tanto el contenido como la escena sean accesibles e interactivos.

🎯Gestión de pointer-events

CRÍTICO: El container de SplineBackground debe usar el preset FIXED_FULLSCREEN_INTERACTIVE
✓ Hacer: Usar pointer-events-none en capas de overlay y contenido
✗ Evitar: Divs con pointer-events-auto sobre la escena que bloqueen la interacción

📐Arquitectura de Capas

z-0SplineBackground (interactivo)
z-[1]Overlay de gradiente (pointer-events-none)
z-10Contenido (pointer-events-none en container)
---Elementos interactivos (pointer-events-auto individual)

🎨Contraste y Legibilidad

  • • Usa gradientes oscuros/claros según el fondo de la escena
  • • Aplica backdrop-blur-sm para efecto glassmorphism
  • • Divide la pantalla (50/50) para separar contenido y escena
  • • El overlay debe cubrir solo el área del contenido

📱Responsive Design

  • • Usa BACKGROUND_RESPONSIVE para posicionamiento adaptativo
  • • En móvil, prioriza el contenido sobre la interacción 3D
  • • Considera ocultar la escena en pantallas pequeñas si es pesada
  • • Usa grid lg:grid-cols-2 para layout adaptativo

⚠️Errores Comunes a Evitar

No eliminar las capas bloqueantes: Si hay un div con z-index superior al canvas y sin pointer-events-none, bloqueará toda la interacción.
Usar preset incorrecto: El preset por defecto FIXED_FULLSCREEN tiene pointer-events-none, usa FIXED_FULLSCREEN_INTERACTIVE para escenas interactivas.
Contenido que cubre toda la pantalla: Si el contenido no está limitado a un lado, bloqueará la escena. Usa grid de 2 columnas o limita el ancho.
Aplicar pointer-events granularmente: Container con pointer-events-none, elementos interactivos con pointer-events-auto.

Ejemplo de estructura correcta

<div className="relative min-h-screen">
{/* Capa 1: Escena 3D (z-0, interactiva) */}
<SplineBackground
scene={SPLINE_SCENES.KEYBOARD}
preset="BACKGROUND_RESPONSIVE"
container="FIXED_FULLSCREEN_INTERACTIVE" // ← IMPORTANTE
className="fixed inset-0 z-0"
/>
{/* Capa 2: Overlay de gradiente (z-1, no interactivo) */}
<div className="fixed left-0 top-0 bottom-0 w-full md:w-1/2
bg-linear-to-r from-black/60 to-transparent
z-1 pointer-events-none" /> {/* ← No bloquea interacción */}
{/* Capa 3: Contenido (z-10) */}
<div className="relative z-10 min-h-screen flex items-center
pointer-events-none"> {/* ← pointer-events-none en container */}
<div className="grid lg:grid-cols-2 gap-12">
{/* Contenido izquierda - interactivo */}
<div className="space-y-8 pointer-events-auto"> {/* ← auto solo aquí */}
<h1>WebCode</h1>
<button>Click me</button> {/* ← Este botón funciona */}
</div>
{/* Espacio derecho - NO bloquear la escena */}
<div className="hidden lg:block pointer-events-none" /> {/* ← none */}
</div>
</div>
</div>

Consejos Importantes

Optimización de Archivos

  • • Usa archivos .splinecode optimizados
  • • Implementa lazy loading para escenas pesadas
  • • Considera usar CDN para archivos grandes

Manejo de Estados

  • • Siempre maneja estados de carga
  • • Implementa fallbacks para errores
  • • Usa loading states para mejor UX