I've been using value timers to animate the positions of sprites. For convenience, I've been using vector2Ds so I can achieve this with a single timer (see A list of helpful libraries and code - #125 by Ebs). This works great, although it seems there's a bug: if both the startValue and endValue vectors are zero in the x component (in other words, y-axis-only animations), then the interpolation short circuits and the timer reports the supplied endValue as the current value for the full duration of the timer.
Here's a repro:
local x1, y1, x2, y2 = 0, 100, 0, 0 -- fails
-- local x1, y1, x2, y2 = 0.00001, 100, 0, 0 -- works
-- local x1, y1, x2, y2 = 100, 0, 0, 0 -- works
-- local x1, y1, x2, y2 = 0, 100, 1, 0 -- works
-- local x1, y1, x2, y2 = 100, 0, 1, 0 -- works
local v1 = playdate.geometry.vector2D.new(x1, y1)
local v2 = playdate.geometry.vector2D.new(x2, y2)
local t = playdate.timer.new(100, v1, v2)
t.updateCallback = function(t) print(t.value) end