summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 08:55:06 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit137e784bb617438bec5079ec5fef4b16ce8b75fe (patch)
treec1f16aa27c18e1e1aeeade4502201e084d998a52 /src
parentbdb4da01c555337fe08167e420b06a3e3f5548ff (diff)
downloadpardes-137e784bb617438bec5079ec5fef4b16ce8b75fe.tar.gz
pardes-137e784bb617438bec5079ec5fef4b16ce8b75fe.zip
T4: the terminal's dissolve swaps cells in ordered (Bayer) order
animation.dissolveRevealed (the tty compositor's dissolve and the pointer mapping that follows it) swaps each changed cell once at its place in a 4x4 Bayer matrix, shifted by the pane's serial so two panes differ, instead of at a hashed noise threshold: the new content comes in as an even patterned screen (§9.2 T4). Endpoints stay exact. Tests: a 4x4 block reveals exactly t x 16 cells at t = 1/4, 1/2, 3/4. Snapshots unchanged. Feel review: .scratch/render/tty/dissolve/ (the matrix over two real frames; the recorded session's pane did not animate, noted in docs/effects.md).
Diffstat (limited to 'src')
-rw-r--r--src/animation.zig19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/animation.zig b/src/animation.zig
index 713a8a30..b682c770 100644
--- a/src/animation.zig
+++ b/src/animation.zig
@@ -313,11 +313,18 @@ pub fn cellNoise(serial: u32, col: u16, row: u16) f32 {
/// Whether a changed dissolve cell has crossed from the frozen old grid to
/// the new one. Exact endpoints are part of the presentation contract.
+/// T4 (§9.2): an ordered swap, each cell at its place in a 4x4 Bayer
+/// matrix (shifted by the pane's serial so two panes differ), so the new
+/// content comes in as an even, patterned screen rather than noise, and
+/// each cell swaps once.
pub fn dissolveRevealed(serial: u32, col: u16, row: u16, raw_progress: f32) bool {
const t = std.math.clamp(raw_progress, 0.0, 1.0);
if (t <= 0) return false;
if (t >= 1) return true;
- return cellNoise(serial, col, row) < t;
+ const bayer = [4][4]u8{ .{ 0, 8, 2, 10 }, .{ 12, 4, 14, 6 }, .{ 3, 11, 1, 9 }, .{ 15, 7, 13, 5 } };
+ const x = (@as(u32, col) +% serial) % 4;
+ const y = (@as(u32, row) +% serial / 4) % 4;
+ return (@as(f32, @floatFromInt(bayer[y][x])) + 0.5) / 16 < t;
}
pub const CellArea = struct {
@@ -624,6 +631,16 @@ test "opening presets separate geometry and content transitions" {
try std.testing.expect(closing.amount() < progress(.vertical, closing.frame));
}
+test "the ordered dissolve reveals a 4x4 block evenly, each cell once" {
+ for ([_]f32{ 0.25, 0.5, 0.75 }) |t| {
+ var revealed: usize = 0;
+ for (0..4) |y| for (0..4) |x| {
+ if (dissolveRevealed(7, @intCast(x), @intCast(y), t)) revealed += 1;
+ };
+ try std.testing.expectEqual(@as(usize, @intFromFloat(t * 16)), revealed);
+ }
+}
+
test "dissolve has exact stable endpoints" {
for (0..64) |col| {
const x: u16 = @intCast(col);