Not a full answer, but the descriptors completely describe the shape of the data for the encoder/decoder. The encoder/decoder don't actually look at the value itself (the value being serialized) when deciding how to write/read. (Except for contextual maybe, but don't worry about that)
So basically an encoder gets a value, and asks the descriptor "hey, what am I looking at?". and based on the element name/index/kind/etc. it can figure out what to do.
As for how to create the descriptor... yeah I agree there can definitely be clearer documentation (which is a tough task for such a complicated API/library, and probably why the class/method docs are so technical instead of intuitive). I usually poke through
the docs, and for anything more complicated than class serializers (list, maps, polymorphic, ...), I poke through serializers in the kotlinx.serialization source to see how they're written