tldraw offline is the local whiteboard for you and your agents.Download the app

BlogProduct

Rigging the system

Leo Knudsen

Hi, it’s Leo, tldraw intern here.

Yesterday we launched tldraw flash, our lightweight animation tool built on the SDK.

Now that you’ve had some time to play with it, I wanted to tell you a bit about how we built the rig that allows you to customize the animated characters.

The rigging system that allows you to customize the character was also custom-built on top of the mechanics already used for the canvas. We created a tool called Riglab, which allows us to author each animation (like waving, sitting, and kicking). In previous iterations, you could drag the characters around limb by limb; in this final version, we settled on a hybrid between frame-by-frame animation and keyframe animation.

Here’s how I did it.

From fairies to Guy

The fairy from our tldraw fairies was animated frame-by-frame using SVGs and sprite sheets. So I wanted something that kept that style while allowing me to make something catered to tldraw flash’s emotes. To do this, you choose a frame, and you choose what pose is made in that frame.

If you move a limb, that pose is stored for that frame. Then, for the in-between frames, the poses interpolate so that the animation is smooth. But this interpolation happens through my own forward kinematics (FK) blending system.

Choose a frame, pose the arm, then play the animation in Riglab Frames

I kept what’s controlled by the rig to things that can be expressed relatively and combined when needed, like rotation and reach, rather than pure local position. In this way, interpolation happens around angles rather than positions, and blending between poses feels more like a figure.

This also makes the animation compatible with different humanoid rigs. Technically, I could change the proportions, like longer legs or a longer torso, and still make the animation work, since what’s being done is adding deltas to the base pose. The command isn’t “move the arm here”; the command is “rotate this arm this much and extend it by this factor”.

The arms have an “extension” factor, which I call reach, so that an arm can be longer or shorter. This is a compromise between not doing inverse kinematics (IK) for motion and still having a hint of an elbow, while also bringing in a sense of foreshortening to allow for more diverse poses.

The same arm handle controls rotation and reach.

It’s all rigged

I also built explicit control over how each value of the rig gets blended. For each pose, they have different values of rotation/reach to describe a pose. When you do multiple poses at the same time, those values mix in certain ways. This is a feature that’s uniquely necessary for emotes in tldraw flash, because the emotes shouldn’t actually move the figure’s position itself—they need to stay relative to the figure’s box. That’s because all parts of the rig are in the local space of the figure’s box. So moving, scaling, flipping, or doing anything to the box doesn’t affect the figure’s motion inside.

Then, for the figure’s full-body motion, I only allowed tilt and vertical shifts. I explicitly categorised them as “secondary animations”, as opposed to the limbs’ motion, so full-body motion blends between poses differently from limb poses.

Body tilt and vertical shift use separate controls in Riglab Frames

Full-body motions blend by stacking on top of each other. If a walk and a kick trigger at the same time, the figure will tilt its body for the kick, while also taking influence from the micro-tilts that come from walking.

Walking on its own, and with Kick layered over it

Within the limbs, I can explicitly choose which limbs blend with the walk. For example, for kicks, the kicking leg shouldn’t walk while kicking, so that limb will play the full emote animation. Other limbs, like the grounded leg, can still blend with the walk animation.

Integrating into tldraw flash

The main challenge of integrating this into tldraw flash is saving the poses to clips when the figure itself is animated procedurally.

If the figure kept animating procedurally within clips, there would be performance concerns as well as consistency concerns, since the animation would change based on the conditions. So clips contain the actual data of the rig’s rotation, reach, body tilt, and vertical shift, as raw values sampled at up to 30 fps. I went for this rather than saving the positions of the figure’s inner shapes themselves, since the figure is also customizable, and with more customization there would be more things to update per frame.

Scaling the clip should still keep the figure intact, and you have to be able to do punch-ins without introducing any noticeable snapping. So clips also save which emote the figure is playing and how far through it is. If you do a punch-in, the figure will smoothly transition back to being procedurally animated and perform the next user input.

Record, scrub back into the clip, then punch in and continue the performance

The UI for the style menu has gone through a lot of iterations, to both tell the user that they can do emotes and that there are shortcut keys for them, while still feeling like a tldraw style menu. For the icons, by default the code finds the pose within the animation that is farthest away from that animation’s base pose and uses it as an icon. This way, if someone adds a new animation, they don’t need to worry about the thumbnail, and it also works with customized figures.

The style menu shows the emote icons and their shortcut keys

Finally, I added a system where the user can make the rig hold things and wear things as hats. In terms of technical detail, the holding system was added as a way of introducing rigid animation to let the figure interact with props without deforming them, while the figure edit feature handles more stretchy animation, which allows for more forgiving customization.

A drawing held in the hand and another worn as a hat, during Wave and Dance
For now, we’d love to see what you make! Share your animations with us on X and LinkedIn, or join our Discord server.

Trusted by these companies

  • AlAI
  • bigpi
  • CADChat
  • Google
  • Replit
  • BlackRock
  • Loveable
  • ClickUp
  • Autodesk
  • Google Stitch
  • Luma
  • Runway
  • SchoolAI
  • Honeycomb
  • Padlet
  • Genio
  • JAM
  • Mobbin
  • Brisk
  • Aries
  • Dirac