This tutorial walks by way of creating an interactive animation: beginning in Blender by designing a button and simulating a cloth-like object that drops onto a floor and settles with a gentle bounce.
After baking the fabric simulation, the animation is exported and introduced right into a Three.js undertaking, the place it turns into an interactive scene that may be replayed on click on.
By the tip, you’ll have a user-triggered animation that blends Blender’s physics simulations with Three.js rendering and interactivity.
Let’s dive in!
Step 1: Create a Dice and Add Subdivisions
- Begin a New Challenge: Open Blender and delete the default dice (choose it and press X, then affirm).
- Add a Dice: Press Shift + A > Mesh > Dice to create a brand new dice.
- Enter Edit Mode: Choose the dice, then press Tab to modify to Edit Mode.
- Subdivide the Dice: Press Ctrl + R so as to add a loop minimize, hover over the dice, and scroll your mouse wheel to extend the variety of cuts.
- Apply Subdivision: With the dice nonetheless chosen in Object Mode, go to the Modifiers panel (wrench icon), and click on Add Modifier > Subdivision Floor. Set the Ranges to 2 or 3 for a smoother end result, then click on Apply.

Step 2: Add Material Physics and Alter Settings
- Choose the Dice: Guarantee your subdivided dice is chosen in Object Mode.
- Add Material Physics: Go to the Physics tab within the Properties panel. Click on Material to allow material simulation.
- Pin the Edges (Elective): If you would like components of the dice to remain mounted (e.g., the highest), swap to Edit Mode, choose the vertices you need to pin, return to the Physics tab, and beneath Material > Form, click on Pin to assign these vertices to a vertex group.
- Alter Key Parameters:
- High quality Steps: Set to 10-15 for smoother simulation (greater values improve accuracy however decelerate computation).
- Mass: Set to round 0.2-0.5 kg for a lighter, extra versatile material.
- Stress: Below Material > Stress, allow it and set a optimistic worth (e.g., 2-5) to simulate inflation. This can make the fabric broaden as if air is pushing it outward.
- Stiffness: Alter Pressure and Compression (e.g., 10-15) to manage how stiff or unfastened the fabric feels.
- Take a look at the Simulation: Press the Spacebar to play the animation and see the fabric inflate. Tweak settings as wanted.

Step 3: Add a Floor Aircraft with a Collision
- Create a Floor Aircraft: Press Shift + A > Mesh > Aircraft. Scale it up by urgent S and dragging (e.g., scale it to 5-10x) so it’s giant sufficient for the fabric to work together with.
- Place the Aircraft: Transfer the airplane under the dice by urgent G > Z > -5 (or alter as wanted).
- Allow Collision: Choose the airplane, go to the Physics tab, and click on Collision. Depart the default settings.
- Run the Simulation: Press the Spacebar once more to see the fabric inflate and settle onto the bottom airplane.


Step 4: Alter Supplies and Textures
- Choose the Dice: In Object Mode, choose the fabric (dice) object.
- Add a Materials: Go to the Materials tab, click on New to create a cloth, and identify it.
- Set Base Shade/UV Map: Within the Base Shade slot, select a fabric-like coloration (e.g., purple or blue) or join a picture texture by clicking the yellow dot subsequent to Base Shade and choosing Picture Texture. Load a texture file when you’ve got one.
- Alter Roughness and Specular: Set Roughness to 0.1-0.3 for a gentle cloth look.
- Apply to Floor (Elective): Repeat the method for the airplane, utilizing a easy grey or textured materials for distinction.

Step 5: Export as MDD and Generate Form Keys for Three.js
To make use of the fabric animation in a Three.js undertaking, we’ll export the physics simulation as an MDD file utilizing the NewTek MDD plugin, then re-import it to create Form Keys. Comply with these steps:
- Allow the NewTek MDD Plugin:
- Go to Edit > Preferences > Add-ons.
- Seek for “NewTek” or “MDD” and allow the “Import-Export: NewTek MDD format” add-on by checking the field. Shut the Preferences window.
- Apply All Modifiers and All Remodel:
- In Object Mode, choose the fabric object.
- Go to the Modifiers panel (wrench icon). For every modifier (e.g., Subdivision Floor, Material), click on the dropdown and choose Apply. This “freezes” the mesh with its present form and physics information.
- Guarantee no unapplied deformations (e.g., scale) stay: Press Ctrl + A > All Transforms to use location, rotation, and scale.
- Export as MDD:
- With the fabric object chosen, go to File > Export > Lightwave Level Cache (.mdd).
- Within the export settings (backside left):
- Set FPS (frames per second) to match your undertaking (e.g., 24, 30, or 60).
- Set the Begin/Finish Body of your animation.
- Select a save location (e.g., “inflation.mdd”) and click on Export MDD.
- Import the MDD:
- Go to File > Import > Lightwave Level Cache (.mdd), and cargo the “inflation.mdd” file.
- Within the Physics and Modifiers panel, take away any material simulation-related choices, as we now have form keys.

Step 6: Export the Material Simulation Object as GLB
After importing the MDD, choose the dice with the animation information.
- Export as glTF 2.0 (.glb/.gltf): Go to File > Export > glTF 2.0 (.glb/.gltf).
- Examine Form Keys and Animation
- Below the Information part, examine Form Keys to incorporate the morph targets generated from the animation.
- Examine Animations to export the animation information tied to the Form Keys.
- Export: Select a save location (e.g., “inflation.glb”) and click on Export glTF 2.0. This file is now prepared to be used in Three.js.
Step 7: Implement the Material Animation in Three.js
On this step, we’ll use Three.js with React (by way of @react-three/fiber) to load and animate the fabric inflation impact from the inflation.glb file exported in Step 6. Under is the code with explanations:
- Set Up Imports and File Path:
- Import obligatory libraries: THREE for core Three.js performance, useRef, useState, useEffect from React for state and lifecycle administration, and utilities from @react-three/fiber and @react-three/drei for rendering and controls.
- Import GLTFLoader from Three.js to load the .glb file.
- Outline the mannequin path: const modelPath = ‘/inflation.glb’; factors to the exported file (alter the trail based mostly in your undertaking construction).
- Create the Mannequin Part:
- Outline the Mannequin part to deal with loading and animating the .glb file.
- Use state variables: mannequin for the loaded 3D object, loading to trace progress, and error for dealing with points.
- Use useRef to retailer the AnimationMixer (mixerRef) and animation actions (actionsRef) for controlling playback.
- Load the Mannequin with Animations:
- In a useEffect hook, instantiate GLTFLoader and cargo inflation.glb.
- On success (gltf callback):
- Extract the scene (gltf.scene) and create an AnimationMixer to handle animations.
- For every animation clip in gltf.animations:
- Set period to six seconds (clip.period = 6).
- Create an AnimationAction (mixer.clipAction(clip)).
- Configure the motion: clampWhenFinished = true stops on the final body, loop = THREE.LoopOnce performs as soon as, and setDuration(6) enforces the 6-second period.
- Reset and play the motion instantly, storing it in actionsRef.present.
- Replace state with the loaded mannequin and set loading to false.
- Log loading progress with the xhr callback.
- Deal with errors within the error callback, updating error state.
- Clear up the mixer on part unmount.
- Animate the Mannequin:
- Use useFrame to replace the mixer every body with mixerRef.present.replace(delta), advancing the animation based mostly on time.
- Add interactivity:
- handleClick: Resets and replays all animations on click on.
- onPointerOver/onPointerOut: Adjustments the cursor to point clickability.
- Render the Mannequin:
- Return null if nonetheless loading, an error happens, or no mannequin is loaded.
- Return a
factor with the loaded mannequin, enabling shadows and attaching occasion handlers.
- Create a Reflective Floor:
- Outline MetalGround as a mesh with a airplane geometry (args={[100, 100]}).
- Apply MeshReflectorMaterial with properties like metalness=0.5, roughness=0.2, and coloration=”#202020″ for a metallic, reflective look. Alter blur, power, and determination as wanted.
- Set Up the Scene:
- Within the App part, create a
- Add a directionalLight at [0, 15, 0] with shadows enabled.
- Embody an Atmosphere preset (“studio”) for lighting, a Mannequin at [0, 5, 0], ContactShadows for realism, and the MetalGround rotated and positioned under.
- Add OrbitControls for interactive digicam motion.
import * as THREE from 'three';
import { useRef, useState, useEffect } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Atmosphere, MeshReflectorMaterial, ContactShadows } from '@react-three/drei';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
const modelPath = '/inflation.glb';
operate Mannequin({ ...props }) {
const [model, setModel] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const mixerRef = useRef(null);
const actionsRef = useRef([]);
const handleClick = () => {
actionsRef.present.forEach((motion) => {
motion.reset();
motion.play();
});
};
const onPointerOver = () => {
doc.physique.model.cursor = 'pointer';
};
const onPointerOut = () => {
doc.physique.model.cursor = 'auto';
};
useEffect(() => {
const loader = new GLTFLoader();
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
loader.setDRACOLoader(dracoLoader);
loader.load(
modelPath,
(gltf) => {
const mesh = gltf.scene;
const mixer = new THREE.AnimationMixer(mesh);
mixerRef.present = mixer;
if (gltf.animations && gltf.animations.size) {
gltf.animations.forEach((clip) => {
clip.period = 6;
const motion = mixer.clipAction(clip);
motion.clampWhenFinished = true;
motion.loop = THREE.LoopOnce;
motion.setDuration(6);
motion.reset();
motion.play();
actionsRef.present.push(motion);
});
}
setModel(mesh);
setLoading(false);
},
(xhr) => {
console.log(`Loading: ${(xhr.loaded / xhr.whole) * 100}%`);
},
(error) => {
console.error('An error occurred loading the mannequin:', error);
setError(error);
setLoading(false);
}
);
return () => {
if (mixerRef.present) {
mixerRef.present.stopAllAction();
}
};
}, []);
useFrame((_, delta) => {
if (mixerRef.present) {
mixerRef.present.replace(delta);
}
});
if (loading || error || !mannequin) {
return null;
}
return (
);
}
operate MetalGround({ ...props }) {
return (
);
}
export default function App() {
return (
);
}
And that’s it! Starting from a cloth simulation in Blender, we turned it into a button that drops into place and reacts with a bit of bounce inside a Three.js scene.
This workflow shows how Blender’s physics simulations can be exported and combined with Three.js to create interactive, real-time experiences on the web.