intro
tweak
codegen
simplify
misc

TLDR

give animation → get line array

Drop an animation (e.g. an .fbx from mixamo) onto this tool, and it turns it into an array of lines for each frame in the animation.

draw lines → get stickman

The "codegen" tab has an array literal in your language; there are also integration examples demonstrating how to use these arrays to create the basic "stickman renderer" in a language/graphics backend of your choosing.

why?

prototyping/custom engines

This is useful for game jams and rapidly prototyping games before you know exactly what you want your character to feel like; head size, torso:leg ratios, etc. are parameterized, so you can get a feel for the proportions you want your character to have. (see the "tweak" tab)

This is especially true if you're making a custom engine for your game, and you haven't spent the time to make a skeletal animation system yet.

why? stickman games! flash homages

Stickmen are endearing and low lift. If you can pull off the aesthetic, you don't need to do a ton of work, especially if you can just drop in mixamo animations. You can make up for the lack of graphical fidelity with cool procedural animations. (dismemberment, ragdolls, etc.)

why? procedural animations

Even if you've got full skeletal animations in Unity/Unreal, you may want to run procedural animations (person-shaped singe marks on the ground, ragdolls, etc.) on a simplified version of your skeleton - you might use this tool to quickly check what parts of your skeleton are worth keeping.


            

          

Animations from e.g. mixamo have many more joints than a simple stickman needs, so we hide most of them and then add back a couple connections so he doesn't have big ole holes in him.

If you hover over a joint on the canvas (it helps to pause the animation first), you can see what its name will be below.

added connections

ignored joints

The following blender export script gives you a JSON similar to the output of this tool.

# blender export script
import bpy
import json     

def write_bone_positions(armature, output_file=None):
    frames = []
    bone_connections = []

    if armature.type != 'ARMATURE':
    print("Error: Selected object is not an armature.")
      return

    for bone in armature.pose.bones:
        if len(bone.children) > 0:
            for child_bone in bone.children:
                bone_connections.append([bone.name, child_bone.name])

    start_frame = bpy.context.scene.frame_start
    end_frame = bpy.context.scene.frame_end
    for frame in range(start_frame, end_frame):
        bpy.context.scene.frame_set(frame)

        bone_poses = {}

        for bone in armature.pose.bones:
            # Get the location of the bone in world space
            p = armature.matrix_world @ bone.head
            bone_poses[str(bone.name)] = { 'x': p.x, 'y': p.y, 'z': p.z }

            frames.append(bone_poses)

         with open("./bone_frames.json", "w+") as fp:
             json.dump({ 'frames': frames, 'connections': bone_connections }, fp)

write_bone_positions(bpy.context.object)