# Animation Stress Test Model

**URL:** <https://forum.babylonjs.com/t/animation-stress-test-model/60721>\
**Category:** Demos and projects\
**Tags:** animation, gltf, tests, performance\
**Created:** [September 30, 2025, 8:44am UTC](https://forum.babylonjs.com/t/animation-stress-test-model/60721 "2025-09-30T08:44:07Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![kzhsw](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@kzhsw](https://forum.babylonjs.com/u/kzhsw)\
**Post date:** [September 30, 2025, 8:44am UTC](https://forum.babylonjs.com/t/animation-stress-test-model/60721/1 "2025-09-30T08:44:07Z")

</div>

This is created by blender and optimized by gltf-transform, containing 4000 nodes and 12000 animation channels, can be used in benchmarking and stress test.  
All models here are provided for free, and if anyone want a license, CC0 or WTFPL.  
[AnimationStressTest4000.zip](https://forum.babylonjs.com/uploads/short-url/nsGYbmUgijBVBrc8okzFw3jzOn7.zip) (6.7 MB)

And one with 10k nodes and 30k animation channels.  
[AnimationStressTest10k.zip](https://forum.babylonjs.com/uploads/short-url/mOw6h6ppKXsFOc0nWMhmbJPaqSV.zip) (5.5 MB)

To benchmark animation, rendering overhead is minimalized with instancing:

 ![sandbox screenshot](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/9/6/964d2aaef1d3e1600998d72b8f352e7125bae479.png)

And a typical profile should just like:

 ![chrome profile](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/c/6/c6ca5ef941141071eae1ad8863598907e779ab32.png)  
 ![chrome profile2](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/0/b/0b9f4586715419450570615704cf21de53291f0f.png)

The script to create the model is here, code is shared under WTFPL:

```python
import bpy
import random
import math

# Function to create a mesh object using built-in primitives
def create_builtin_mesh(mesh_type, name):
    if mesh_type == 'CUBE':
        bpy.ops.mesh.primitive_cube_add(size=1, enter_editmode=False, align='WORLD', location=(0, 0, 0))
    elif mesh_type == 'SPHERE':
        bpy.ops.mesh.primitive_uv_sphere_add(radius=1, enter_editmode=False, align='WORLD', location=(0, 0, 0))
    elif mesh_type == 'CONE':
        bpy.ops.mesh.primitive_cone_add(radius1=1, depth=2, enter_editmode=False, align='WORLD', location=(0, 0, 0))
    
    # Get the last created object
    obj = bpy.context.object
    obj.name = name
    return obj

# Function to animate the object
def animate_object(obj, frame_start, frame_end):
    # Set initial random transformation
    obj.location = (
        random.uniform(-100, 100),
        random.uniform(-100, 100),
        random.uniform(-100, 100)
    )
    obj.rotation_euler = (
        random.uniform(0, 2 * math.pi),
        random.uniform(0, 2 * math.pi),
        random.uniform(0, 2 * math.pi)
    )
    obj.scale = (
        random.uniform(0.5, 2),
        random.uniform(0.5, 2),
        random.uniform(0.5, 2)
    )
    
    # Insert keyframes for the start
    obj.keyframe_insert(data_path="location", frame=frame_start)
    obj.keyframe_insert(data_path="rotation_euler", frame=frame_start)
    obj.keyframe_insert(data_path="scale", frame=frame_start)

    # Set final random transformation
    obj.location = (
        random.uniform(-100, 100),
        random.uniform(-100, 100),
        random.uniform(-100, 100)
    )
    obj.rotation_euler = (
        random.uniform(0, 2 * math.pi),
        random.uniform(0, 2 * math.pi),
        random.uniform(0, 2 * math.pi)
    )
    obj.scale = (
        random.uniform(0.5, 2),
        random.uniform(0.5, 2),
        random.uniform(0.5, 2)
    )
    
    # Insert keyframes for the end
    obj.keyframe_insert(data_path="location", frame=frame_end)
    obj.keyframe_insert(data_path="rotation_euler", frame=frame_end)
    obj.keyframe_insert(data_path="scale", frame=frame_end)

    # Set interpolation to linear
    for fcurve in obj.animation_data.action.fcurves:
        for keyframe in fcurve.keyframe_points:
            keyframe.interpolation = 'LINEAR'

# Clear existing objects
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.object.delete()

# Create 4,000 unique meshes using built-in primitives
mesh_types = ['CUBE', 'SPHERE', 'CONE']
for i in range(4000):
    mesh_type = random.choice(mesh_types)
    mesh_obj = create_builtin_mesh(mesh_type, f"Mesh_{i}")
    
    # Animate the object over 1 minutes (60 seconds at 24 fps)
    animate_object(mesh_obj, frame_start=1, frame_end=60 * 24)

# Set the scene frame range
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 60 * 24

```

And the model can be loaded into playground:

> **[Babylon.js Playground](https://playground.babylonjs.com/#HVYHNC)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL and WebGPU 3D scenes
