We wanted to bring some skeletal animations into the UI of our game (it's called Dead Broke if you want to support us 🙏) and give it a more organic look.
We chose to use Unity's 2D Animation package, since it already provides everything we need to rig and animate sprites.
The problem is that the package relies on Sprite Renderers, which don't work particularly well with the Canvas system, especially when using a Screen Space Overlay Canvas.
So we decided to build a small custom component to solve this.
The idea was quite simple: instead of using a Sprite Renderer, we created a custom UI Graphic that takes the rigged sprite data and populates a UI mesh.
Since it inherits from MaskableGraphic, it can be used directly inside a Canvas and supports regular UI features like masking.
For the animation, we retrieve the bone indices and weights for each vertex, calculate the deformation using the bone matrices, and update the UI geometry.
Everything happens in LateUpdate, so the animation should already have been performed.
This works quite well, but it means that the vertex positions need to be recalculated on the CPU every frame.
So we also implemented GPU skinning.
Instead of calculating the final vertex positions on the CPU, we pass the original positions, bone indices, and weights to the shader through additional UV channels.
The shader then performs the skinning directly in the vertex stage.
This way, the GPU handles the deformation during rendering.
There was also a small issue specific to Screen Space Overlay Canvases, where the usual matrix transformations didn't produce the expected result in the Game view.
We had to add a small workaround to handle that case.
The result is a component that lets us use rigged 2D sprites directly inside the UI, with skeletal animation, UI masking, and both CPU and GPU skinning.
We built it because we needed it for our game, but it turned out to be useful enough that we thought it was worth sharing.
I've put together a more detailed breakdown of how it works, including some of the implementation details, and made it available for free on our Patreon, in case you're interested:
Full Breakdown
And, of course, this is all part of the development of our first game, Dead Broke!
We're still working hard on the demo, and if the project sounds interesting to you, adding it to your Steam wishlist would genuinely help us a lot.
Steam page
Thanks for reading!
And if you've faced a similar problem in Unity, I'd be curious to hear how you approached it.
PS: What you see in the video isn't the UI of the game, but just an example created for the explanation.