Animating a ValueObject to harness TweenService for standard values is a not unheard of yet hacky solution.
For a comprehensive system, animations could generally be represented with one function that receives the time it’s been playing for. A main animation loop would run the function for whatever animation is selected to play (by string id, assuming you stored the animation functions in a table) and keep track of playing time for that function.
Linear would be implemented by default in these functions, (as most animations tend to be,) but could be augmented by TweenService:GetValue() or your own easing/wave functions. Thoughts?