How to convert MMD files to JSON for three.js

Posted :

I published a video, which is explaining the way to convert MMD files ( PMX and VMD ) to a JSON file for three.js.

Here is it.

The convert was operated on Blender.


  • Check the language setting at preference to display Japanese characters.
  • Install and activate following addons

Load MMD files

  1. Load a PMX file
  2. Select all bones
  3. Load a VMD file

Bake Action

some bones of the MMD model are controled by IK or physics. However, three.js does not support IK and physics. Therefore, you need to bake all bones as FK bones.

  1. Select all bones
  2. Press space key, and search “bake action”
  3. Bake all frames, as “Frame Step:1” dont set except “1”. otherwise, bones which are controled by phtsics will not work as expected.
  4. Wait for bake to complete.
  5. Bake all frames again, as Frame Step: around 3, to thin out too much frames. This will reduce the file size.
  6. Wait for bake to complete.
  7. Check the animation.

Remove garbage animations

  1. Switch to Dope Sheet mode
  2. Select Action Editor
  3. Check Actions
  4. Save and close Blender once
  5. Open the file
  6. Check the Actions. Garbage animations should be removed

Replace all multibyte (Japanese) characters

  • Switch to Text Editor mode
  • Make a new text
  • Copy and paste the script below, and then, press Run Script
import bpy

for obj in = 'obj'

for mesh in = 'mesh'

for armature in = 'arm'

  for bone in armature.bones: = 'b'

for material in = 'm'

Fix the rest pose

Fix the rest pose. To do so, press control + A, and then check all transforms.


Make sure that you checked “Skeltal animation”, and “Copy textures”. if you have already published textures, dont check “Copy textures”. Then, press “Export Three.js”. Publishing may take a few min.

Edit json


Write a JavaScript code

As the result, you will see like this example (about 4MB).

var width  = window.innerWidth,
    height = window.innerHeight,
    clock = new THREE.Clock(),

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera( 40, width / height, 1, 1000 );
camera.position.set( 0, 2, 6 );

renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
document.body.appendChild( renderer.domElement );

var ambientLight = new THREE.AmbientLight( 0xffffff )
scene.add( ambientLight );

var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( .5, 1, .5 ).normalize();
scene.add( directionalLight );

scene.add( new THREE.GridHelper( 10, 1 ) );

loader = new THREE.JSONLoader();
loader.load( 'miku.js', function( geometry, materials ) {
  materials.forEach(function ( mat ) {
    mat.skinning = true;
    // mat.wireframe = true;
  } );

  miku = new THREE.SkinnedMesh(
    new THREE.MeshFaceMaterial( materials )

  THREE.AnimationHandler.add( miku.geometry.animations[ 0 ] );

  action = new THREE.Animation(
    miku.geometry.animations[ 0 ].name,
  scene.add( miku );;
} );

( function renderLoop (){
  requestAnimationFrame( renderLoop );
  var delta = clock.getDelta();
  THREE.AnimationHandler.update( delta );
  renderer.render( scene, camera );
} )();