Sorry, totally missed your reply!
At first we had normal text and then we switched them for hand-drawn sprites. The text animation consists of 2D transformations (translation, rotation, scale) interpolated over time. It's all animated in code. NanoVG helps by having a transformation stack like OpenGL. In Zig I can open a block like this:
{ vg.save(); defer vg.restore(); // undo all transformations at the end of the block
vg.translate(...);
vg.rotate(...);
vg.scale(...);
// draw sprite
}
// continue to draw the rest of the scene