From 2809aa88097894a33ab4f486c2053c225397f5b7 Mon Sep 17 00:00:00 2001 From: planadecu Date: Tue, 14 Jul 2026 16:46:50 +0200 Subject: [PATCH] Clear out-of-band graphics on unmount Kitty/ghostty images live in a separate graphics plane that text repaints never erase, and the double-buffer only deletes the previous image on the next render. When the host app unmounts the chart (e.g. switching to a table or log view), no further render happens, so the last chart lingered on screen over whatever replaced it. Add an unmount cleanup that deletes both buffered kitty image IDs. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01SCHVP8VywU8i8JAN4xgLVs --- src/InkUPlot.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/InkUPlot.tsx b/src/InkUPlot.tsx index abdc261..ef2abe2 100644 --- a/src/InkUPlot.tsx +++ b/src/InkUPlot.tsx @@ -127,6 +127,19 @@ export function InkUPlot({ // Reserved box for out-of-band graphics — we read its on-screen position to place the image. const boxRef = useRef(null); + // On unmount (e.g. the host app switches to a table or log view), erase the image. + // Kitty/ghostty images live in a separate graphics plane that text repaints never + // clear — and the double-buffer below only deletes the previous image on the *next* + // render, which never comes once the chart is gone. Without this the last chart + // lingers on screen over whatever replaces it. Both buffer IDs are deleted to be safe. + useEffect(() => { + return () => { + if (isKitty(format)) { + process.stdout.write(kittyDelete(1) + kittyDelete(2)); + } + }; + }, [format]); + // Clear stale output when dimensions change (not needed for kitty — bypasses Ink) useEffect(() => { if (!isRawFormat(format)) { setOutput(null); setError(null); }