summaryrefslogtreecommitdiff
path: root/src/Messages.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 20:31:56 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commitc5c2baf21bba0fb8f66e7d2ee096818d6bd5a8e0 (patch)
tree6cd19cfb7fbd076433fbb965e8a52ac1800949fb /src/Messages.zig
parent242467eb9f066f80164d534be55c2c4ebc9b5604 (diff)
downloadpardes-c5c2baf21bba0fb8f66e7d2ee096818d6bd5a8e0.tar.gz
pardes-c5c2baf21bba0fb8f66e7d2ee096818d6bd5a8e0.zip
Motion flavours differ by design, and drive notice drops and pane moves
The flavours looked alike because Lift, the only motion that read them, moves a shadow a few pixels: overshoot and wind-up were sub-pixel. By design now: crisp leaves at full speed and never passes its mark; smooth (the default) eases in and out in twice crisp's time, a slide arriving in 208 ms (inside ยง8.1's 220); bouncy passes its mark by ~30% and settles twice; playful winds up, passes by ~40%, and stretches and squashes, text included (the user's choice). Small motions are exaggerated by the flavour's gain. Motion gains launch, gain, span and norm, and ease(u)/speed(u) for moves of fixed length. The notice drop follows ease() over its fall (alpha never behind its position) and stays inside its pane's body past its row. Panel tracks carry the flavour in Track.motion (the old padding byte; macOS header name follows); opening and moving slides, zooms and rises follow it over span x their frames; landed, a pane is exactly its target; closing keeps its own exit. A pane past its mark never takes a neighbour's click; a rising one stays in its box. Tests: each flavour's lift trajectory distinct; flavour character; exact landing bit for bit; a stretched pane's drawn cells map back; the overshoot hit rule; the vertical clip at peak; legacy tests pinned to crisp. GUI golden 18-mid-transition changes (the retuned smooth slide at frame 6). Shared files: src/animation.zig, src/Presentation.zig, src/Messages.zig, src/macos.zig, src/config.zig, src/pardes.zig tests, src/ninep/screen.zig test, docs/effects.md, docs/config.md.
Diffstat (limited to 'src/Messages.zig')
-rw-r--r--src/Messages.zig10
1 files changed, 8 insertions, 2 deletions
diff --git a/src/Messages.zig b/src/Messages.zig
index ea62041f..800218b7 100644
--- a/src/Messages.zig
+++ b/src/Messages.zig
@@ -356,11 +356,14 @@ pub fn messageMotion(p: *const Pardes, life: Pane.MessageLife) MessageMotion {
// last frames only settle it. No overshoot: at a row's height
// and a dozen frames, a follow-through is a pixel or two that
// reads as a jitter, not a bounce.
- const left = 1 - t;
+ // The drop follows the Motion flavour (its wind-up, overshoot
+ // and all) over the fall's length.
+ const left = 1 - animation.Motion.of(p.settings.motion).ease(t);
// The colour leads the motion: solid by half way, so what
// lands is already legible rather than still fading up.
const faded = 1 - @min(1, 2 * t);
- break :blk .{ .alpha = 1 - faded * faded, .slide = -(left * left * left) };
+ // And never behind it, however fast the flavour leaves.
+ break :blk .{ .alpha = @max(1 - faded * faded, std.math.clamp(1 - left, 0, 1)), .slide = -left };
},
.leaving => blk: {
// Counted to its last frame rather than past it, so that frame
@@ -644,6 +647,9 @@ test "a message falls in, lingers past the input that dismisses it, and dissolve
while (p.nextEffect()) |_| {}
const pane = p.panes[p.active].?;
try std.testing.expect(p.settings.message_animation);
+ // Crisp: the flavour whose drop leaves at full speed and lands without
+ // passing its row (the others are the Motion tests').
+ p.settings.motion = .crisp;
try std.testing.expect(p.executeBuiltinLine(p.active, "MessageLinger 160"));
try std.testing.expect(p.executeBuiltinLine(p.active, "Msg hello"));
try std.testing.expectEqual(Pane.MessagePhase.entering, pane.msg_life.phase);