Interactive 3D Demo (Vanilla JS)

by Samin Sami

HTML

<!-- Tailwind CSS CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Preload Spline runtime for faster loading -->
    <link rel="preload" href="https://unpkg.com/@splinetool/runtime@1.2.6/build/runtime.js" as="script">

    <main class="min-h-screen">
        <div class="max-w-6xl mx-auto">
            <header class="mb-12">
                <h1 class="text-3xl font-bold">Interactive 3D Demo</h1>
                <p class="text-gray-400 mt-2">Experience the power of Spline 3D in Vanilla JS</p>
            </header>

            <section class="mb-12">
                <!-- Main card with 3D scene - Increased height and adjusted layout -->
                <div id="spline-scene-basic-card" class="w-full h-[700px] bg-black/[0.96] relative overflow-hidden rounded-lg border border-gray-800 shadow-xl">
                    <!-- Spotlight effect -->
                    <div id="spotlight-element"
                         class="spotlight"
                         style="width: 200px; height: 200px; transition: transform 0.1s ease-out;">
                    </div>

                    <div class="flex h-full flex-col md:flex-row">
                        <!-- Left content - Reduced width -->
                        <div class="md:w-2/5 p-6 md:p-8 relative z-10 flex flex-col justify-center">
                            <h3 class="text-4xl md:text-5xl font-bold gradient-text">
                                Interactive 3D
                            </h3>
                            <p class="mt-4 text-neutral-300 max-w-md">
                                Bring your UI to life with beautiful 3D scenes. Create immersive experiences
                                that capture attention and enhance your design.
                            </p>
                            <div class="mt-6">
                                <button class="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md transition-colors">
                ...

CSS

/* Custom styles for the loader */
        .loader {
            width: 48px;
            height: 48px;
            border: 5px solid #FFF;
            border-bottom-color: transparent;
            border-radius: 50%;
            display: inline-block;
            box-sizing: border-box;
            animation: rotation 1s linear infinite;
        }

        @keyframes rotation {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }
        
        /* Additional custom styles */
        .gradient-text {
            background: linear-gradient(to bottom, #f8fafc, #cbd5e1);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }
        
        .spotlight {
            pointer-events: none;
            position: absolute;
            border-radius: 50%;
            background: radial-gradient(circle at center, rgba(248, 250, 252, 0.8), rgba(248, 250, 252, 0.4), transparent 80%);
            filter: blur(20px);
            transition: opacity 0.2s ease-out;
            opacity: 0;
        }

JavaScript

// Initialize Spline scene as soon as possible
        function initSpline() {
            const splineCanvas = document.getElementById('spline-canvas');
            const splineLoader = document.getElementById('spline-loader');
            const splineSceneUrl = "https://prod.spline.design/kZDDjO5HuC9GJUM2/scene.splinecode";

            if (!splineCanvas || !splineLoader) {
                console.error('Required Spline elements not found');
                return;
            }

            // Hide canvas and show loader initially
            splineCanvas.classList.add('hidden');
            splineLoader.classList.remove('hidden');

            // Load Spline runtime dynamically
            import('https://unpkg.com/@splinetool/runtime@1.2.6/build/runtime.js')
                .then(({ Application }) => {
                    try {
                        // Initialize Spline application
                        const app = new Application(splineCanvas);

                        // Load the Spline scene
                        app.load(splineSceneUrl)
                            .then(() => {
                                // Hide loader and show canvas once loaded
                                splineLoader.classList.add('hidden');
                                splineCanvas.classList.remove('hidden');
                                console.log('Spline scene loaded successfully!');
                                
                                // Initialize spotlight effect after scene loads
                                initSpotlight();
                            })
                            .catch(error => {
                                console.error('Failed to load Spline scene:', error);
                                splineLoader.innerHTML = '<p class="text-red-500 text-center">Failed to load 3D scene</p>';
                            });
                    } catch (error) {
                       ...