I don't feel like making a new screenshot so here are some tulips instead.
This is a general overview of the way my character editor works.
To recap from my last post about aiming, all of the objects in the editor are nodes in a hierarchy. They are derived from a base class that I call TransformNode. The specialized nodes that I have so far are the Joint, IKHandle, and Quad. Joints are nodes that form a skeleton and can be affected by IK, IKHandles are nodes that control an IK chain (of joints), and Quads are the textured quads that make up the visible part of an entity.
All nodes contain a collection of attributes that are used in animation. The base node has translation and rotation attributes, and specialized nodes can add other attributes to the collection. The Quad, for example, has additional attributes for width, height, and texture coordinates. (This means that texture/sprite animation can be used in combination with skeletal animation.) New attributes are animateable as soon as they are added to the node and exposed to the interface (via a public property with get/set accessors so that they show up in the property grid).
Attributes are animated by setting keyframes in the animation curve that is associated with that attribute. A curve contains a set of keyframes and a reference to the node it affects, along with the attribute index. Keyframes contain data for control points on the animation curve and their tangents. The positions of the points on the curve are the frame of the animation (x) and the value of the attribute at that frame (y). Bezier interpolation is used to interpolate the values between keyframes. An animation is simply a set of curves.
Aim animations have an additional bit of data called an AimVector. It has minimum and maximum rotation values and is attached to a node in the hierarchy. Aim animations are like regular animations except that there are only two keyframes. When aiming, the angle of the vector between the aim vector node position and the target position is compared to the minimum and maximum angles to get an interpolation value. This value is used to do a linear interpolation between the two frames of the aim animation.
When exporting animations, the curve data is interpolated and values are saved for every frame in the animation (so that interpolation does not need to be performed in game).
This editor has evolved a lot over the time I've been working on it. I'm finally satisfied with this particular implementation, although a lot of the functionality was copied from Maya.