That too is solvable by eliminating local state and has an advantage of making animation time travel debugging possible.

So in my comment above I mentioned having a component export two functions. One function is a pure render function and one function creates a state instance. The state of the animation would be one of the things tracked in the state instance:

var Observable = require('observ');
var svg = require('virtual-dom/virtual-hyperscript/svg');

module.exports = state;
module.exports = render;

function state(initialPosition) {
return new Observable(initialPosition || [0,0]);
}

function render(positionState) {
var center = positionState();
return svg('circle', {
'fill': 'rgba(255, 0, 0, 0.1)',
'stroke': 'black',
'stroke-width': '2',
'cx': center[0],
'cy': center[1],
'r': 10
});
}

The parent component would export its state in the same way. Its own state would be composed by calling the state() function of its own subcomponents. Turtles all the way down.

At the top of the app, the saved state would be injected into the state of the top level component, which would decompose it into parts and inject it into the state functions of its subcomponents such as the one above.

This single composed state object tree makes it trivial to record diffs in state for playback or to serialize and save the state to localStorage or the network.

It's trivial to work with the approach above. As trivial as the local state approach of react. It's extremely consistent about where state lives. It doesn't sometimes live in a global place and sometimes live in some other place. Another developer joining the project doesn't have to hunt around for where state for a particular value is being maintained. It also makes it simple to do far more complex things with animation, like build a complex animation editing application where an animation might be controlled by knobs, buttons, sliders, dials, etc. With local state you'd have to wire up those controls directly to the internal state of a component, completely messing up separation of concerns. With the composed state object, you just write one function that maps the state of two sliders (x&y) to the state of the circle and have it listen to change events on the slider position. It's trivial to wire things up in both directions by having them listen to each other.

Time travel (undo/redo) is also trivial to implement:
https://github.com/Raynos/mercury/blob/master/time-travel.js
67 LOC with generous whitespace.

You could wire up the time-travel state to a slider as well to accomplish something like this:
https://www.youtube.com/watch?v=ri614C_Buwg

For the viewing state over time features in the froggato level editor you simply take the series of state over time, use it to instantiate state() multiple times and render them all in the same frame.

Show one circle:

scene -> circleRender(circleStateAtTimePosition(now));

Show one circle over time:

scene -> circleRender(circleStateAtTimePosition(now - 2));
-> circleRender(circleStateAtTimePosition(now - 1));
-> circleRender(circleStateAtTimePosition(now));
-> circleRender(circleStateAtTimePosition(now + 1));
-> circleRender(circleStateAtTimePosition(now + 2));

Local state simply makes everything much harder to reason about as you move beyond all but the most trivial apps.

Lastly, for long running ephemeral state animations, you gain the ability to "cancel" the animation. Imagine you have a "card" animating out from the right to show a panel, but you click on something else that would close that panel and open another one. It's much simpler to cancel that animation midway, close the first card and animate out the second card. The alternative is to add a bunch of methods to the card class to handle the cancellation logic. If you need that cancellation logic in other components you need a mixin, but it's all brittle because its tied to the key names on this.props as opposed to being able to make a animation controlling function used in an animation coordinator that merely needs to receive cursors (i.e. nothing is hard coded to key names)

You might say "but I have no reason to track ephemeral state in that way" and you would be correct, you don't need to. But there are no disadvantages of doing so relative to local state. Furthermore you gain predictability about where state lives and the ability to not worry about refactoring if one day decide that you want to now control a particular piece of ephemeral state.