Могу предложить для ясности вот такое решение:
import sys
from time import sleep
def cut_frame(s: str, start_pos: int = 0, frame_size: int = None) -> str:
frame_size = frame_size or len(s)
left_space = ' ' * min(start_pos, frame_size)
if start_pos < 0:
s = s[-start_pos:]
return f'{(left_space + s)[:frame_size]:{frame_size}}'
def scroll(s: str, frame_size: int = None, timeout: float = 0.1, template: str = '[{}]', file=sys.stdout):
frame_size = frame_size or min(len(s), 80)
for i in range(-len(s), frame_size + 1)[::-1]:
substring = template.format(cut_frame(s, i, frame_size))
print(substring, end='\033[0G', flush=True, file=file)
sleep(timeout)
В виндовом терминале не пробовал, но если ANSI-последовательности поддерживаются, то должно скроллиться как положено.