One unused set of abstractions for animations is enough.
N2TXVDIYJWHD2CA4MA4O6P74FBAA5CLNCMZNOXRSQH5R24RH7Q2QC 2NEL7TGNFKBDFSJMCHLI5UQ65UWYSMDZPG3ZV24TOFRPJK2NQBLAC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC 2Q437U4FVEYO3Y22OC3NC5MAYVEDTTCWCRJHBKHKWA4WZSPWYUDQC PFSJMMNJSMEYMQLHDXXNUT2DULCLKWIPEICMVBEYY6E4OSCBJWGAC SW5GN5LPJX6DBQ7IEE4WYZ6XZLLHXNO7BENCQ6LRCYMIBKNZQFMQC ZM7NOBRMD5HHA35Y4JDC76EOA2RD4KQOQCPURXYKXA6ABMKOJIGQC 5RUFNRJOK3PXQKJTPDEN5K5PI67MGB25QUA44WOCCH2O5KHXT45QC UEG224LHBOPWSKOVXTKVAUEL47HET566LJF7ZSWVKMMLBSJWUHFAC -- update any in-progress animations-- return whether any work remainsdraw_next_frames_of_animations = function()local a = Animations_in_progressfor i=#a,1,-1 doif coroutine.status(a[i].co) == 'dead' thentable.remove(a, i)elselocal status, err = coroutine.resume(a[i].co)if status == false then error(err) endendendreturn #a > 0end
-- A debugging aid to help animate intermediate results within f.-- Pause animation in the current frame using loiter().-- Try to only have one such call in your program.-- You can have multiple, but things might get confusing if one of them indirectly calls the other,-- or more generally if a single function ever loiters sometimes under the call tree of one and sometimes under the other.enable_loiter = function(f, ...)local args = {...}Error_with_callstack = nillocal co = coroutine.create(function()xpcall(function()f(unpack(args))end,save_callstack)end)coroutine.resume(co, ...)if Error_with_callstack thenerror(Error_with_callstack)endtable.insert(Debug_animations_in_progress, {co=co, next_run=Current_time+0.3})end