Widget System

One of the big steps I've done to make my game engine ready for actually start making games with is that I created a widget system for it.

Reason

A widget system is by no means required to make a game, but if the game plans on having any UI more complex than a simple menu, it will make the UI so much easier to create and manage than trying to handle the huge amount of loose sprites that need custom behaviour to work the way you want. I'm developing it alongside a card tracking program for my Magic the Gathering collection as a way to test the system and to find out what it lacks, also just because I wanted to make such a program.

Design

My main references for how it should work has been how HTML/CSS works and the widget system in Unreal Engine, since those are what I've worked with the most before, but I also wanted to fix some annoyances I've had with them from a programming standpoint. The main thing I wanted to do with my system that I haven't seen others do is having everything live in parent space, that's to say having all widget transform values be relative to the transform values of their parent. This was because I've felt that these systems I've used were needlessly confusing to work with due to the units specified not always behaving like I expect them to, and thought that making everything always relative to their parent would make it easier for me to design things.
Now that I've created the system and actually worked with it I understand the UI design problems this causes. There are cases where you want things to have a certain size on the screen and not scale depending on the size of the containing parent widget, or have a minimum/maximum screen space size. However I don't think that makes this system unusable or fundamentally flawed, only not as neatly designed as I hoped it would be, because these problems can always be fixed by making widget types that enforces the sizing constraints needed.

Optimization

While working on this system I've done a lot of optimizations. Some because I noticed it was running slow and some just because I had an idea of how to make it better.
A good example of something I've done several rounds of optimizations on is how it updates widgets. Using a lot of caching has made it possible to have several thousands of children in a scrolling list without impacting performance.