Exporting 2d bone animation from Blender to vanilla JavaScript
Blender is an awesome free animation tool. It focuses on 3d animation, but it's also great for 2d. Let's import animation created in Blender to JavaScript - the stickman above is being drawn realtime on an HTML5 Canvas by JS. As you can see, I suck at character animation, but Blender offers great functionality like Inverse Kinematics, keyframes, interpolation, pose library etc.:
Blender comes with a built-in Python interpreter. Here's a short snippet that exports the coordinates of the bones to a "coords.js" file:
import bpy |
import os |
with open('c:/javascript/coords.js', 'w') as file: |
file.write('let coords=[') |
bones = ['spine','head','arm.l','forearm.l','thigh.l','shin.l','arm.r','forearm.r','thigh.r','shin.r'] |
for f in range(226): |
bpy.context.scene.frame_set(f) |
p = bpy.data.objects['Armature'].location + bpy.data.objects['Armature'].pose.bones['spine'].head |
file.write(str(round(p.x)) + ',' + str(round(p.y)) + ',') |
for n in range(10): |
p = bpy.data.objects['Armature'].location + bpy.data.objects['Armature'].pose.bones[bones[n]].tail |
file.write(str(round(p.x)) + ',' + str(round(p.y)) + ',') |
file.write('];') |
Click here for simple step-by-step instructions if you're new to Blender Python.
Click here to download the .blend animation file for Blender (this is optional)
It actually generates a one line JS program that just creates the "coords" array. We have a little animated armature (skeleton) consisting of several bones (spine, head, arms, forearms etc). The script first opens the output file, then goes through every frame and writes the x and y coordinates of every bone to the file, separated by commas. The first point is the head of the spine (Blender calls the starting point of a bone a "spine", but in this situation it is ironically placed on the character's butt) and following points are located at the bones' "tails". We're doing a 2d animation here to keep things simple, but the same concept would work for three dimensions.
Now the JS part:
<html> |
<body> |
<canvas id="myCanvas" width="600" height="600"></canvas> |
<script src='coords.js' type='text/javascript'></script> |
<script> |
let frame = 0; |
let canvas = document.getElementById('myCanvas'); |
let context = canvas.getContext('2d'); |
|
function line(p1, p2) { |
context.beginPath(); |
context.moveTo(p1.x, p1.y); |
context.lineTo(p2.x, p2.y); |
context.stroke(); |
} |
|
function draw() { |
context.clearRect(0, 0, 600, 600); |
let points = []; |
for (let n = 0; n < 11; n++) { |
let point = { |
x: coords[frame * 2 * 11 + n * 2], |
y: 400 - coords[frame * 2 * 11 + n * 2 + 1] |
}; |
points.push(point); |
} |
context.beginPath(); |
context.arc(points[2].x, points[2].y, 30, 0, 2 * Math.PI); |
context.stroke(); |
line(points[0], points[1]); |
line(points[1], points[3]); |
line(points[3], points[4]); |
line(points[0], points[5]); |
line(points[5], points[6]); |
line(points[1], points[7]); |
line(points[7], points[8]); |
line(points[0], points[9]); |
line(points[9], points[10]); |
frame++; |
if (frame == 226) |
frame = 0; |
window.requestAnimationFrame(draw); |
} |
|
context.lineWidth = 10; |
context.lineCap = 'round'; |
draw(); |
|
</script> |
</body> |
</html> |
[4] imports the coordinates file generated by Python
[10-15] function that draws a line from Point 1 to Point 2
[17-43] the main animation loop:
[18] clear the previous frame
[20-26] create an array of 11 points for the given frame. Each point is an object with x and y coordinates.
[27-38] draw a circle for the head and lines for spine and limbs. To make it look better, you can draw .png or .svg images instead of these simple shapes.
This is a relatively simple example to demonstrate the idea. You could make it more interesting (and complicated) by having multiple characters and their actions (jump, fall etc) and locations driven by the user.