Possibly the call to the animation is blocking and thus it only reads the button
if (digitalRead(BTN_PIN) == LOW)
once in a while.
if you want the system to be reactive, you need to come read the button often and can't have a blocking animation call
as a first try, call ws2812fx.service() only when animation is due (I don't know that library)
also set last_change with a negative value (-TIMER_MS at least) so that it's taken into account