powershellbatch-fileanimationterminal

How to prevent flickering caused by cls in a batch script?


I have been working on a batch script which has some sort of animated intro, My first thought was to use cls to clear the console before every frame, but that caused horrible flickering, as shown in this video https://streamable.com/o34k0e.

this is the batch code I used:

@echo off
chcp 65001 >nul
setlocal enabledelayedexpansion

::
:loop
cls
for /L %%A in (1,1,20) do (
    cls
    call :frame %%A
    ping -n 1 -w 300 127.0.0.1 >nul
)
goto loop

goto :eof

:frame
:: full letters
set "letters1=  █     █░▓█████  ██▓     ▄████▄   ▒█████   ███▄ ▄███▓▓█████"
set "letters2= ▓█░ █ ░█░▓█   ▀ ▓██▒    ▒██▀ ▀█  ▒██▒  ██▒▓██▒▀█▀ ██▒▓█   ▀"
set "letters3= ▒█░ █ ░█ ▒███   ▒██░    ▒▓█    ▄ ▒██░  ██▒▓██    ▓██░▒███"
set "letters4= ░█░ █ ░█ ▒▓█  ▄ ▒██░    ▒▓▓▄ ▄██▒▒██   ██░▒██    ▒██ ▒▓█  ▄"
set "letters5= ░░██▒██▓ ░▒████▒░██████▒▒ ▓███▀ ░░ ████▓▒░▒██▒   ░██▒░▒████▒"
set "letters6= ░ ▓░▒ ▒  ░░ ▒░ ░░ ▒░▓  ░░ ░▒ ▒  ░░ ▒░▒░▒░ ░ ▒░   ░  ░░░ ▒░ ░"
set "letters7=   ▒ ░ ░   ░ ░  ░░ ░ ▒  ░  ░  ▒     ░ ▒ ▒░ ░  ░      ░ ░ ░  ░"
set "letters8=   ░   ░     ░     ░ ░   ░        ░ ░ ░ ▒  ░      ░      ░"
set "letters9=     ░       ░  ░    ░  ░░ ░          ░ ░         ░      ░  ░"
set "letters10=                         ░"

:: play dripping effect by changing characters in the lines 5, 6, 7, 8, 9
if %1 lss 5 (
    set "letters5=%letters5:▒= %"
) else if %1 lss 10 (
    set "letters6=%letters6:░= %"
) else if %1 lss 15 (
    set "letters7=%letters7:▒= %"
) else if %1 lss 20 (
    set "letters8=%letters8:░= %"
) else if %1 lss 25 (
    set "letters9=%letters9:▓= %"
)

:: display the letters with the "dripping" effect
echo.
echo !letters1!
echo !letters2!
echo !letters3!
echo !letters4!
if defined letters5 echo !letters5!
if defined letters6 echo !letters6!
if defined letters7 echo !letters7!
if defined letters8 echo !letters8!
if defined letters9 echo !letters9!
echo !letters10!
goto :eof

And I also tried using PowerShell which also failed to even display a second frame, as seen here:

# UTF-8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# define the letters for the animation
$lines = @(
    "  █     █░▓█████  ██▓     ▄████▄   ▒█████   ███▄ ▄███▓▓█████",
    " ▓█░ █ ░█░▓█   ▀ ▓██▒    ▒██▀ ▀█  ▒██▒  ██▒▓██▒▀█▀ ██▒▓█   ▀",
    " ▒█░ █ ░█ ▒███   ▒██░    ▒▓█    ▄ ▒██░  ██▒▓██    ▓██░▒███",
    " ░█░ █ ░█ ▒▓█  ▄ ▒██░    ▒▓▓▄ ▄██▒▒██   ██░▒██    ▒██ ▒▓█  ▄",
    " ░░██▒██▓ ░▒████▒░██████▒▒ ▓███▀ ░░ ████▓▒░▒██▒   ░██▒░▒████▒",
    " ░ ▓░▒ ▒  ░░ ▒░ ░░ ▒░▓  ░░ ░▒ ▒  ░░ ▒░▒░▒░ ░ ▒░   ░  ░░░ ▒░ ░",
    "   ▒ ░ ░   ░ ░  ░░ ░ ▒  ░  ░  ▒     ░ ▒ ▒░ ░  ░      ░ ░ ░  ░",
    "   ░   ░     ░     ░ ░   ░        ░ ░ ░ ▒  ░      ░      ░  ░",
    "     ░       ░  ░    ░  ░░ ░          ░ ░         ░      ░  ░",
    "                         ░"
)

# loop for animation
while ($true) {
    # clear the console
    Clear-Host

    # loop through each line to create the dripping effect
    for ($i = 0; $i -lt $lines.Count; $i++) {
        $line = $lines[$i]
        
        # changq certain characters based on their index
        if ($i -ge 4 -and $i -lt 9) {
            if ($i -eq 4) { $line = $line -replace '▒', ' ' }
            elseif ($i -eq 5) { $line = $line -replace '░', ' ' }
            elseif ($i -eq 6) { $line = $line -replace '▒', ' ' }
            elseif ($i -eq 7) { $line = $line -replace '░', ' ' }
            elseif ($i -eq 8) { $line = $line -replace '▓', ' ' }
        }
        
        # the modified line
        Write-Host $line
    }

    # wait before refreshing the display
    Start-Sleep -Milliseconds 300
}

Batch code to execute the PowerShell file:

@echo off
chcp 65001 >nul
PowerShell -NoProfile -ExecutionPolicy Bypass -File "%~dp0drip-animation.ps1"
pause


Solution

  • # Define the lines for the animation
    $lines = @'
      █     █░▓█████  ██▓     ▄████▄   ▒█████   ███▄ ▄███▓▓█████
     ▓█░ █ ░█░▓█   ▀ ▓██▒    ▒██▀ ▀█  ▒██▒  ██▒▓██▒▀█▀ ██▒▓█   ▀
     ▒█░ █ ░█ ▒███   ▒██░    ▒▓█    ▄ ▒██░  ██▒▓██    ▓██░▒███
     ░█░ █ ░█ ▒▓█  ▄ ▒██░    ▒▓▓▄ ▄██▒▒██   ██░▒██    ▒██ ▒▓█  ▄
     ░░██▒██▓ ░▒████▒░██████▒▒ ▓███▀ ░░ ████▓▒░▒██▒   ░██▒░▒████▒
     ░ ▓░▒ ▒  ░░ ▒░ ░░ ▒░▓  ░░ ░▒ ▒  ░░ ▒░▒░▒░ ░ ▒░   ░  ░░░ ▒░ ░
       ▒ ░ ░   ░ ░  ░░ ░ ▒  ░  ░  ▒     ░ ▒ ▒░ ░  ░      ░ ░ ░  ░
       ░   ░     ░     ░ ░   ░        ░ ░ ░ ▒  ░      ░      ░  ░
         ░       ░  ░    ░  ░░ ░          ░ ░         ░      ░  ░
                             ░
    '@ -split '\r?\n'
    
    [Console]::Clear()
    [Console]::CursorVisible = $false
    
    foreach ($i in 1..20) {
    
      [Console]::SetCursorPosition(0, 0)
    
      [Console]::Write($lines -join "`n")
    
      Start-Sleep -Milliseconds 300
    
      if ($i -lt 5) { $lines[4] = $lines[4] -replace '▒', ' ' }
      elseif ($i -lt 10) { $lines[5] = $lines[5] -replace '░', ' ' }
      elseif ($i -lt 15) { $lines[6] = $lines[6] -replace '▒', ' ' }
      elseif ($i -lt 20) { $lines[7] = $lines[7] -replace '░', ' ' }
      elseif ($i -lt 25) { $lines[8] = $lines[8] -replace '▓', ' ' }
    
    }
    [Console]::CursorVisible = $true