I’ve at all times been eager about discovering easy methods to deliver extra depth into net interfaces, not simply via visuals, however via interplay and area.
On this demo, I explored how flat UI playing cards can develop into interactive 3D scenes utilizing GLB fashions, Three.js, and Webflow. Every card begins as a primary structure however reveals a small, self-contained surroundings constructed with real-time rendering and refined movement.
It’s a light-weight method to including spatial storytelling to acquainted elements, utilizing instruments many designers already work with.
Welcome to My Inventive World
I’m at all times drawn to visuals that blend the futuristic with the acquainted — space-inspired kinds, minimal layouts, and on a regular basis components seen from a unique angle.
Most of my tasks begin this manner: by reimagining strange concepts via a extra immersive or atmospheric lens.
It All Began with a Moodboard
This one started with a easy inspiration board:

From that board, I picked a couple of of my favourite visuals and ran them via an AI device that converts pictures into GLB 3D fashions.
The outcomes have been surprisingly good! Summary, textured, and stuffed with character.

The Idea: Flat to Deep
After I noticed the output from the AI-generated GLB fashions, I began fascinated with how we understand depth in UI design, not simply visually, however interactively.
That led to a easy concept: what if flat playing cards might reveal a hidden spatial layer? Not via animation alone, however via precise 3D geometry, lighting, and digital camera motion.
I designed three UI playing cards, every styled with minimal HTML and CSS in Webflow. On interplay, they load a novel GLB mannequin right into a Three.js scene instantly throughout the card container. Every mannequin is lit, framed, and animated to create the sensation of a self-contained 3D area.

Constructing the Internet Expertise
The structure was inbuilt Webflow utilizing a easy flexbox construction with three playing cards inside a wrapper. Every card accommodates a div
that serves because the mounting level for a 3D object.
The GLB fashions are rendered utilizing Three.js, which is built-in into the challenge with customized JavaScript. Every scene is initialized and dealt with individually, giving every card its personal interactive 3D area whereas conserving the structure light-weight and modular.

Scene Design with Blender
Every GLB mannequin was ready in Blender, the place I added a surrounding sphere to create a way of depth and environment. This straightforward form helps simulate background distinction and encloses the item in a self-contained area.
Lighting performed an vital position; particularly with reflective supplies like glass or steel. Highlights and comfortable shadows have been used to create that refined, futuristic glow.
The result’s that every 3D mannequin feels prefer it lives inside its personal ambient surroundings, even when rendered in a small card.

Bringing It Along with Three.js
As soon as the fashions have been exported from Blender as .glb
recordsdata, I used Three.js to render them inside every card. Every card container acts as its personal 3D scene, initialized via a customized JavaScript perform.
The setup entails making a primary scene with a perspective digital camera, ambient and directional lighting, and a WebGL renderer. I used GLTFLoader
to load every .glb
file and OrbitControls
to allow refined rotation. Zooming and panning are disabled to maintain the interplay targeted and managed.
Every mannequin is loaded right into a separate container, making it modular and straightforward to handle. The digital camera is offset barely for a extra dynamic beginning view, and the background is stored darkish to assist the lighting pop.
Right here’s the total JavaScript used to load and render the fashions:
// 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 perform initializes a Three.js scene inside a given container
* and hundreds a .glb mannequin into it.
*/
perform createScene(containerSelector, glbPath) {
const container = doc.querySelector(containerSelector);
// 1. Create a scene
const scene = new THREE.Scene();
scene.background = new THREE.Colour(0x202020); // darkish background
// 2. Arrange the digital camera with perspective
const digital camera = new THREE.PerspectiveCamera(
45, // Discipline of view
container.clientWidth / container.clientHeight, // Facet ratio
0.1, // Close to clipping airplane
100 // Far clipping airplane
);
digital camera.place.set(2, 0, 0); // Offset to the aspect for higher 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 mild = new THREE.DirectionalLight(0xffffff, 4);
mild.place.set(30, -10, 20);
scene.add(mild);
const ambientLight = new THREE.AmbientLight(0x404040); // comfortable mild
scene.add(ambientLight);
// 5. Arrange OrbitControls to permit rotation
const controls = new OrbitControls(digital 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; // easy motion
// 6. Load the GLB mannequin
const loader = new GLTFLoader();
loader.load(
glbPath,
(gltf) => {
scene.add(gltf.scene); // Add mannequin to the scene
},
(xhr) => {
console.log(`${containerSelector}: ${(xhr.loaded / xhr.whole) * 100}% loaded`);
},
(error) => {
console.error(`Error loading ${glbPath}`, error);
}
);
// 7. Make it responsive
window.addEventListener("resize", () => {
digital camera.facet = container.clientWidth / container.clientHeight;
digital camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
});
// 8. Animate the scene
perform animate() {
requestAnimationFrame(animate);
controls.replace(); // updates rotation easily
renderer.render(scene, digital camera);
}
animate(); // begin the animation loop
}
// 9. Initialize scenes for every card (exchange together with your URLs)
createScene(".div", "https://yourdomain.com/fashions/yourmodel.glb");
createScene(".div2", "https://yourdomain.com/fashions/yourmodel2.glb");
createScene(".div3", "https://yourdomain.com/fashions/yourmodel3.glb");
This script is added through a tag, both within the Webflow web page settings or as an embedded code block. Every name to
createScene()
initializes a brand new card, linking it to its corresponding .glb
file.
How This Works in Observe
In Webflow, create three containers with the lessons .div
, .div2
, and .div3
. Each will act as a canvas for a unique 3D scene.
Embed the JavaScript module proven above by putting it simply earlier than the closing