From 908815b5851a364ce187209a6397840a9f3eb9ae Mon Sep 17 00:00:00 2001 From: "R.Eugenio" Date: Sat, 3 Jan 2026 12:04:04 +0100 Subject: [PATCH] fix(animation): ColorTransition epsilon para convergencia garantizada MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problema: lerpU8 truncaba incrementos <1, causando que las animaciones nunca terminaran. Con delta_ms=16ms y duration=500ms, el factor t=0.032 hacía que diferencias de 1 (ej: 99→100) nunca convergieran. Solución: Añadir epsilon check después del lerp. Si la diferencia en cada canal RGBA es ≤1, forzar snap al target y devolver false. Esto elimina los redraws infinitos en idle reportados por el usuario. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/render/animation.zig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/render/animation.zig b/src/render/animation.zig index 074f643..dd5205b 100644 --- a/src/render/animation.zig +++ b/src/render/animation.zig @@ -739,6 +739,19 @@ pub const ColorTransition = struct { .a = lerpU8(self.current.a, target.a, t), }; + // EPSILON FIX: Forzar convergencia cuando estamos "suficientemente cerca" + // Sin esto, lerpU8 trunca incrementos <1 y la animación nunca termina. + // Umbral de 1 es imperceptible al ojo pero garantiza convergencia. + const dr = @abs(@as(i16, self.current.r) - @as(i16, target.r)); + const dg = @abs(@as(i16, self.current.g) - @as(i16, target.g)); + const db = @abs(@as(i16, self.current.b) - @as(i16, target.b)); + const da = @abs(@as(i16, self.current.a) - @as(i16, target.a)); + + if (dr <= 1 and dg <= 1 and db <= 1 and da <= 1) { + self.current = target; // Snap al target + return false; // Animación terminada + } + return true; }