I ran a few quick experiments. Coalescing the requestAnimationFrame calls does nothing for CPU usage/performance. The way to go is to pause the widget once the animation is done playing.
The widget API already has a method called "pause" which you can use to prevent the widget from further rendering until you call "play". This will bring CPU usage down to essentially 0 and fits your application.
In your lectures, some events, e.g. modification of the CSS by the user, triggers an animation to be played back. In that case, simply call "setAnimation" followed by "play", then register a callback. Here's a minimal example that will play the "run" animation of Spineboy, then stop rendering (Note: this requires the latest 3.6-beta for the possibility of specifying the callbacks to widget.setAnimation)
<html>
<script src="../../build/spine-widget.js"></script>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<body>
<center>
<div id="spine-widget" style="margin-bottom: 20px; width: 640px; height: 480px;"></div>
</center>
</body>
<script>
spineWidget = new spine.SpineWidget("spine-widget", {
json: "assets/spineboy.json",
atlas: "assets/spineboy.atlas",
animation: "run",
backgroundColor: "#00000000",
debug: true,
success: function (widget) {
spineWidget.setAnimation("run", {
start: function (entry) {},
interrupt: function (entry) {},
end: function(entry) {},
dispose: function(entry) {},
complete: function(entry) {
spineWidget.pause();
},
event: function(entry) {}
});
}
});
</script>
</body>
</html>
With the current state of WebGL, I'm afraid there's no way to get CPU usage down to 0% when doing continuous rendering. The manual pausing is the best we can offer at the moment.