With large projects and hundreds of animate calls, many of which are on the same object and from different sources within the code, you end up with animations interrupting each other when they really shouldn't. This can be worked around to an extent with individual conflicts by making them check for eachother, but client animations are not in sync with the server so the code cannot truly know if an animation is ongoing. Most of the time this isnt too big a deal or very noticeable as the animations are usually short.
Where this becomes unsolvable without other systems is infinitely looping animations. Things like a creature hovering up and down while floating, or some kinds of filters. When you have an ongoing animation like that, any other animate call on that object will interrupt the looping animation. ANIMATION_PARALLEL is supposed to be used to work around this, but this means that every animate call in the project by default should be using it since those call sites have no way of knowing about most of the possible animations that could be ongoing.
So, you write a wrapper for animate() and make them by default use ANIMATE_PARALLEL. New animations no longer cancel existing ones. You can even have two infinitely looping animations on the same object working as intended, until one of them wants to stop that is.
There's currently no way to cancel a specific looping animation on an object. After some discussion the best workaround we could think of, when using purely animate anyway, is to track all ongoing animations and when cancelling one, resume the others using ANIMATION_SLICE.
For a more robust system with less visual issues, you could use render targets to hide the object you want to animate, and animate a proxy instead. Every new animation then has to insert itself into a chain of render targets/sources to avoid having any of them trying to animate the same object. This seems needlessly complex and expensive for something that animate() should be handling itself. So we finally get to the proposal itself.
Proposal
The core desire here is two capabilities:
1. Animations should be individually interruptible
2. Some way to make animations not get interrupted by future animations.
Best way I can see to avoid breaking existing code too much would be to have animate() return a value you can use in place of an object to bring an animation back into "focus", as if it were the last animation started again. ANIMATION_END_NOW has no use currently when used after the first step, it could be used here to cancel specifically that animation.
The following then would start fading something out and changing color, then interrupt just the fade out while the color continues to slowly change
var/foo_id = animate(foo, time=1000, flags=ANIMATION_PARALLEL, alpha=0)
animate(foo, time=1000, flags=ANIMATION_PARALLEL, color="#ff0000")
sleep(300)
animate(foo_id, time=0, flags=ANIMATION_END_NOW, alpha=255)
foo_id here could be either some arbitrary text id, or a full on animation type.
Ideally if implemented in this way, ANIMATION_PARALLEL would make it so it can only be cancelled when cancelled specifically like above, but this would break some existing projects. If you want to avoid this, a new flag like ANIMATION_INDEPENDENT or something could be used instead.
An alternate possibility brought up when discussing this would be to have animation channels. Current behavior could work exactly as is but on independent channels on an object. I'm not so much a fan of having to manage channel usage, but it would deal with the issue here well enough.