That’s the clean way, userData shouldn’t contain methods or references, but it can be added to the base classes Mesh and SkinnedMesh as well (prototype), for a more generic approach as loaded assets already created objects with the base classes.
I use tags which can be added to Object3D based classes, these tags can be singletons or instances. This way controllers can be added as well as temporary effects and such, it’s kinda similar to tags in Cinema 4D.
Events implemented in the tag such as step (frame) and input determine what they will listen to, so this logic is detached from the scene hierarchie to avoid unnecessary traversal in rich scenes.
A controller tag is an object/class (singleton or instance) itself to reuse on assets, for example to control an AI a singleton receieves the objects it has to process while an instance is individual to every object the tag is added to.
I shaped this concept over time with focus on performance and memory, it probably isn’t exactly a common existing concept, maybe a mix or extension, but it fits all needs i have .