New Terminal Output:

root@f3f8d6319494:/app# cat > /app/termzip_ansi.py << 'EOF'
                   changed.append((r, c, curr_row[c]))

        # Group changes by row and decide EL+rewrite vs individual
        row_changes = {}
        for r, c, val in changed:
            row_changes.setdefault(r, []).append((c, val))

        for r, items in row_changes.items():
            curr_row = frames[i][r*w:(r+1)*w]
            # EL+rewrite cost: ESC[r;1H + ESC[2K + row
            cost_erase = 3 + len(str(r+1)) + 1 + 1 + 4 + w
            # Individual cost: sum(ESC[r;cH + char)
            cost_indiv = sum(3 + len(str(r+1)) + 1 + len(str(c+1)) + 1 + 1 for c, _ in items)

            if cost_erase < cost_indiv:
                out.append(f'\x1b[{r+1};1H')
                out.append('\x1b[2K')
                out.append(curr_row.decode('latin1'))
            else:
                for c, val in sorted(items):
                    out.append(f'\x1b[{r+1};{c+1}H')
                    out.append(chr(val))

        out.append('\x1e')

    sys.stdout.write(''.join(out))

if __name__ == '__main__':
    main()
EOF
> import struct
> import sys
>
> def main():
>     if len(sys.argv) != 2:
>         sys.exit(1)
>
>     with open(sys.argv[1], 'rb') as f:
>         magic = f.read(4)
>         if magic != b'TZA1':
>             sys.exit(1)
>         w, h = struct.unpack('<HH', f.read(4))
>         n_frames, max_bytes = struct.unpack('<II', f.read(8))
>         frames = [f.read(w * h) for _ in range(n_frames)]
>
>     out = []
>
>     # Frame 0: write non-space cells individually
>     for r in range(h):
>         row = frames[0][r*w:(r+1)*w]
>         for c in range(w):
>             if row[c] != 32:
>                 out.append(f'\x1b[{r+1};{c+1}H')
>                 out.append(chr(row[c]))
>     out.append('\x1e')
>
>     # Subsequent frames
>     for i in range(1, n_frames):
>         # Find changed cells
>         changed = []
>         for r in range(h):
>             prev_row = frames[i-1][r*w:(r+1)*w]
>             curr_row = frames[i][r*w:(r+1)*w]
>             for c in range(w):
>                 if prev_row[c] != curr_row[c]:
>                     changed.append((r, c, curr_row[c]))
>
>         # Group changes by row and decide EL+rewrite vs individual
>         row_changes = {}
>         for r, c, val in changed:
>             row_changes.setdefault(r, []).append((c, val))
>
>         for r, items in row_changes.items():
>             curr_row = frames[i][r*w:(r+1)*w]
>             # EL+rewrite cost: ESC[r;1H + ESC[2K + row
>             cost_erase = 3 + len(str(r+1)) + 1 + 1 + 4 + w
>             # Individual cost: sum(ESC[r;cH + char)
>             cost_indiv = sum(3 + len(str(r+1)) + 1 + len(str(c+1)) + 1 + 1 for c, _ in items)
>
>             if cost_erase < cost_indiv:
>                 out.append(f'\x1b[{r+1};1H')
>                 out.append('\x1b[2K')
>                 out.append(curr_row.decode('latin1'))
>             else:
>                 for c, val in sorted(items):
>                     out.append(f'\x1b[{r+1};{c+1}H')
>                     out.append(chr(val))
>
>         out.append('\x1e')
>
>     sys.stdout.write(''.join(out))
>
> if __name__ == '__main__':
>     main()
> EOF
root@f3f8d6319494:/app#
