Building Interactive 3D Cards in Webflow with Three.js

A quick guide to integrating interactive 3D models into your Webflow project using Three.js.

I’ve always been interested in finding simple ways to bring more depth into web interfaces, not just through visuals, but through interaction and space.

In this demo, I explored how flat UI cards can become interactive 3D scenes using GLB models, Three.js, and Webflow. Each card starts as a basic layout but reveals a small, self-contained environment built with real-time rendering and subtle motion.

It’s a lightweight approach to adding spatial storytelling to familiar components, using tools many designers already work with.

Welcome to My Creative World

I’m always drawn to visuals that mix the futuristic with the familiar — space-inspired forms, minimal layouts, and everyday elements seen from a different angle.

Most of my projects start this way: by reimagining ordinary ideas through a more immersive or atmospheric lens.

It All Started with a Moodboard

This one began with a simple inspiration board:

From that board, I picked a few of my favorite visuals and ran them through an AI tool that converts images into GLB 3D models.

The results were surprisingly good! Abstract, textured, and full of character.

The Concept: Flat to Deep

When I saw the output from the AI-generated GLB models, I started thinking about how we perceive depth in UI design, not just visually, but interactively.

That led to a simple idea: what if flat cards could reveal a hidden spatial layer? Not through animation alone, but through actual 3D geometry, lighting, and camera movement.

I designed three UI cards, each styled with minimal HTML and CSS in Webflow. On interaction, they load a unique GLB model into a Three.js scene directly within the card container. Each model is lit, framed, and animated to create the feeling of a self-contained 3D space.

Building the Web Experience

The layout was built in Webflow using a simple flexbox structure with three cards inside a wrapper. Each card contains a div that serves as the mounting point for a 3D object.

The GLB models are rendered using Three.js, which is integrated into the project with custom JavaScript. Each scene is initialized and handled separately, giving each card its own interactive 3D space while keeping the layout lightweight and modular.

Scene Design with Blender

Each GLB model was prepared in Blender, where I added a surrounding sphere to create a sense of depth and atmosphere. This simple shape helps simulate background contrast and encloses the object in a self-contained space.

Lighting played an important role; especially with reflective materials like glass or metal. Highlights and soft shadows were used to create that subtle, futuristic glow.

The result is that each 3D model feels like it lives inside its own ambient environment, even when rendered in a small card.

Bringing It Together with Three.js

Once the models were exported from Blender as .glb files, I used Three.js to render them inside each card. Each card container acts as its own 3D scene, initialized through a custom JavaScript function.

The setup involves creating a basic scene with a perspective camera, ambient and directional lighting, and a WebGL renderer. I used GLTFLoader to load each .glb file and OrbitControls to enable subtle rotation. Zooming and panning are disabled to keep the interaction focused and controlled.

Each model is loaded into a separate container, making it modular and easy to manage. The camera is offset slightly for a more dynamic starting view, and the background is kept dark to help the lighting pop.

Here’s the full JavaScript used to load and render the models:

// Import required libraries
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import gsap from 'gsap';

/**
 * This function initializes a Three.js scene inside a given container
 * and loads a .glb model into it.
 */
function createScene(containerSelector, glbPath) {
  const container = document.querySelector(containerSelector);

  // 1. Create a scene
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x202020); // dark background

  // 2. Set up the camera with perspective
  const camera = new THREE.PerspectiveCamera(
    45, // Field of view
    container.clientWidth / container.clientHeight, // Aspect ratio
    0.1, // Near clipping plane
    100  // Far clipping plane
  );
  camera.position.set(2, 0, 0); // Offset to the side for better viewing

  // 3. Create a renderer and append it to the container
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(container.clientWidth, container.clientHeight);
  container.appendChild(renderer.domElement);

  // 4. Add lighting
  const light = new THREE.DirectionalLight(0xffffff, 4);
  light.position.set(30, -10, 20);
  scene.add(light);

  const ambientLight = new THREE.AmbientLight(0x404040); // soft light
  scene.add(ambientLight);

  // 5. Set up OrbitControls to allow rotation
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enableZoom = false; // no zooming
  controls.enablePan = false;  // no dragging
  controls.minPolarAngle = Math.PI / 2; // lock vertical angle
  controls.maxPolarAngle = Math.PI / 2;
  controls.enableDamping = true; // smooth movement

  // 6. Load the GLB model
  const loader = new GLTFLoader();
  loader.load(
    glbPath,
    (gltf) => {
      scene.add(gltf.scene); // Add model to the scene
    },
    (xhr) => {
      console.log(`${containerSelector}: ${(xhr.loaded / xhr.total) * 100}% loaded`);
    },
    (error) => {
      console.error(`Error loading ${glbPath}`, error);
    }
  );

  // 7. Make it responsive
  window.addEventListener("resize", () => {
    camera.aspect = container.clientWidth / container.clientHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(container.clientWidth, container.clientHeight);
  });

  // 8. Animate the scene
  function animate() {
    requestAnimationFrame(animate);
    controls.update(); // updates rotation smoothly
    renderer.render(scene, camera);
  }

  animate(); // start the animation loop
}

// 9. Initialize scenes for each card (replace with your URLs)
createScene(".div",  "https://yourdomain.com/models/yourmodel.glb");
createScene(".div2", "https://yourdomain.com/models/yourmodel2.glb");
createScene(".div3", "https://yourdomain.com/models/yourmodel3.glb");

This script is added via a <script type="module"> tag, either in the Webflow page settings or as an embedded code block. Each call to createScene() initializes a new card, linking it to its corresponding .glb file.

How This Works in Practice

In Webflow, create three containers with the classes .div, .div2, and .div3. Each one will act as a canvas for a different 3D scene.

Embed the JavaScript module shown above by placing it just before the closing </body> tag in your Webflow project, or by using an Embed block with <script type="module">.

Once the page loads, each container initializes its own Three.js scene and loads the corresponding GLB model. The result: flat UI cards become interactive, scrollable 3D objects — all directly inside Webflow.

This approach is lightweight, clean, and performance-conscious, while still giving you the flexibility to work with real 3D content.

Important Note for Webflow Users

This setup works in Webflow, but only if you structure it correctly.

To make it work, you’ll need to:

  • Host your Three.js code externally using a bundler like Vite, Parcel, or Webpack
  • Or bundle the JavaScript manually and embed it as a <script type="module"> in your exported site

Keep in mind: Webflow’s Designer does not support ES module imports (import) directly. Pasting the code into an Embed block won’t work unless it’s already built and hosted elsewhere.

You’ll need to export your Webflow project or host the script externally, then link it via your project settings.

Final Thoughts

Thanks for following along with this project. What started as a simple moodboard turned into a small experiment in mixing UI design with real-time 3D.

Taking flat cards and turning them into interactive scenes was a fun way to explore how much depth you can add with just a few tools: Webflow, Three.js, and GLB models.

If this gave you an idea or made you want to try something similar, that’s what matters most.
Keep experimenting, keep learning, and keep building.

Franco Beltramella

Hey! I’m Franco a creative front-end developer who loves building expressive websites with Webflow, GSAP, and Three.js. I enjoy turning code into playful, immersive interactions. Always experimenting.

The
New
Collective

🎨✨💻 Stay ahead of the curve with handpicked, high-quality frontend development and design news, picked freshly every single day. No fluff, no filler—just the most relevant insights, inspiring reads, and updates to keep you in the know.

Prefer a weekly digest in your inbox? No problem, we got you covered. Just subscribe here.