| 1 |
const std = @import("std");
|
| 2 |
|
| 3 |
pub const Easing = enum {
|
| 4 |
linear,
|
| 5 |
ease_out,
|
| 6 |
ease_in_out,
|
| 7 |
|
| 8 |
pub fn apply(self: Easing, t: f64) f64 {
|
| 9 |
return switch (self) {
|
| 10 |
.linear => t,
|
| 11 |
.ease_out => 1.0 - std.math.pow(f64, 1.0 - t, 3),
|
| 12 |
.ease_in_out => if (t < 0.5)
|
| 13 |
4.0 * t * t * t
|
| 14 |
else
|
| 15 |
1.0 - std.math.pow(f64, -2.0 * t + 2.0, 3) / 2.0,
|
| 16 |
};
|
| 17 |
}
|
| 18 |
};
|
| 19 |
|
| 20 |
pub const Animation_Config = struct {
|
| 21 |
duration_ms: u64 = 150,
|
| 22 |
easing: Easing = .ease_out,
|
| 23 |
};
|
| 24 |
|
| 25 |
pub const Scroll_Animation = struct {
|
| 26 |
start_value: i32 = 0,
|
| 27 |
end_value: i32 = 0,
|
| 28 |
start_time: i64 = 0,
|
| 29 |
duration_ms: u64 = 150,
|
| 30 |
easing: Easing = .ease_out,
|
| 31 |
active: bool = false,
|
| 32 |
|
| 33 |
pub fn start(self: *Scroll_Animation, from: i32, to: i32, config: Animation_Config) void {
|
| 34 |
if (from == to) {
|
| 35 |
self.active = false;
|
| 36 |
return;
|
| 37 |
}
|
| 38 |
self.start_value = from;
|
| 39 |
self.end_value = to;
|
| 40 |
self.start_time = std.time.milliTimestamp();
|
| 41 |
self.duration_ms = config.duration_ms;
|
| 42 |
self.easing = config.easing;
|
| 43 |
self.active = true;
|
| 44 |
}
|
| 45 |
|
| 46 |
pub fn update(self: *Scroll_Animation) ?i32 {
|
| 47 |
if (!self.active) return null;
|
| 48 |
|
| 49 |
const now = std.time.milliTimestamp();
|
| 50 |
const elapsed = now - self.start_time;
|
| 51 |
|
| 52 |
if (elapsed >= @as(i64, @intCast(self.duration_ms))) {
|
| 53 |
self.active = false;
|
| 54 |
return self.end_value;
|
| 55 |
}
|
| 56 |
|
| 57 |
const t = @as(f64, @floatFromInt(elapsed)) / @as(f64, @floatFromInt(self.duration_ms));
|
| 58 |
const eased = self.easing.apply(t);
|
| 59 |
const diff = @as(f64, @floatFromInt(self.end_value - self.start_value));
|
| 60 |
const current = @as(f64, @floatFromInt(self.start_value)) + (diff * eased);
|
| 61 |
|
| 62 |
return @intFromFloat(current);
|
| 63 |
}
|
| 64 |
|
| 65 |
pub fn is_active(self: *const Scroll_Animation) bool {
|
| 66 |
return self.active;
|
| 67 |
}
|
| 68 |
|
| 69 |
pub fn target(self: *const Scroll_Animation) i32 {
|
| 70 |
return self.end_value;
|
| 71 |
}
|
| 72 |
|
| 73 |
pub fn stop(self: *Scroll_Animation) void {
|
| 74 |
self.active = false;
|
| 75 |
}
|
| 76 |
};
|