Ghost-typer effect in batch: Flickering random letters before each character

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
S4M
Posts: 2
Joined: 02 Aug 2025 12:05

Ghost-typer effect in batch: Flickering random letters before each character

#1 Post by S4M » 15 Aug 2025 07:15

Hi everyone,

I’ve been experimenting with a batch “ghost-typer” effect, where text appears on the console as if it’s being typed live. I’d like to enhance it so that before each actual character is printed, a random character flickers in place. This would simulate a “hacking / sci-fi terminal” effect.

Here’s the basic code I started from (from an old Stack Overflow post):

Code: Select all

@echo off
:: Ghost typer
setlocal enableextensions enabledelayedexpansion

set lines=6

set "line1=Twinkle twinkle little star"
set "line2=How I wonder what you are"
set "line3=Up above the world so high"
set "line4=Like a diamond in the sky"
set "line5=Twinkle twinkle little star"
set "line6=How I wonder what you are"

for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"

for /L %%a in (1,1,%lines%) do set num=0&set "line=!line%%a!"&call :type

pause>nul
goto :EOF

:type
set "letter=!line:~%num%,1!"
if not "!letter!"=="" set /p "=a!BS!!letter!" <nul
set /a num+=1
goto :type
Right now, the code types the letters, but the “random flicker” effect is not implemented yet. I’ve tried adding random characters as placeholders, but I’m struggling to make it work reliably while keeping the actual spaces in words intact.

Specifically:

I want each letter to first briefly appear as a random character (chosen from A-Z, 0-9, and some symbols) and then be replaced by the correct letter.
Spaces between words should appear normally.
Timing should be adjustable for a cinematic typing effect.

Some how I manged to do exactly what I wanted some years ago. But sadly ive lost the code :(
Has anyone successfully implemented something like this in pure batch? Any guidance or example code would be greatly appreciated.

Thanks in advance :)

Aacini
Expert
Posts: 1933
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Ghost-typer effect in batch: Flickering random letters before each character

#2 Post by Aacini » 15 Aug 2025 20:48

This code does exactly what you requested...

Code: Select all

@echo off
rem Ghost typer
setlocal EnableDelayedExpansion

set "chars=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
set /A len=62, centiSecs=40, lines=0
for %%a in ("Twinkle twinkle little star"
            "How I wonder what you are" 
            "Up above the world so high"
            "Like a diamond in the sky"
            "Twinkle twinkle little star"
            "How I wonder what you are") do (
   set /A lines+=1
   set "line!lines!=%%~a"
)

for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"

for /L %%a in (1,1,%lines%) do call :type "!line%%a!" < NUL

pause>nul
goto :EOF


:type "line"
set "line=%~1"
:nextLetter
set /A "ran=%random% %% len"
set /P "=!chars:~%ran%,1!!BS!"
call :Delay
set "letter=%line:~0,1%"
set /P "=a!BS!!letter!"
set "line=%line:~1%"
if defined line goto nextLetter
echo/
exit /B


:Delay
set "b=1%time:~-2%"
:wait
   set /A "e=1%time:~-2%, elap=e-b, elap-=(elap>>31)*100"
if %elap% lss %centiSecs% goto wait
exit /B
However, I don't like the final effect... :(

Antonio

IcarusLives
Posts: 184
Joined: 17 Jan 2016 23:55

Re: Ghost-typer effect in batch: Flickering random letters before each character

#3 Post by IcarusLives » 16 Aug 2025 05:05

Here is another way of doing it. Though, I wasn't really sure if you wanted a "ghost typer" or something more along the lines of some "Text being displayed" and then each letter blinking arbitrarily/independently as if there were a faulty light bulb behind it?


Here is text scrambling typer

Code: Select all

@echo off
setlocal enableDelayedExpansion

	               REM "string"  x   y  color
	call :animated_string "%~1" %~2 %~3 %~4

	
exit /b 0


:animated_string
set "string=%~1"
set "frozen="
set /a "string.length=0", "loops=0"
if "%~4" neq "" ( set "hue=%~4" ) else ( set "hue=15" )
set "ascii_str= #$'*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz{}~"

set "loop=FOR /L %%# in (1,1,2) do "
%loop%%loop% set "loop=!loop!!loop!!loop!"

for /l %%b in (8,-1,0) do (
	set /a "string.length|=1<<%%b"
	for %%c in (!string.length!) do if "!string:~%%c,1!" equ "" set /a "string.length&=~1<<%%b"
)
for /l %%i in (0,1,%string.length%) do set "chr[%%i].ch=!string:~%%i,1!"

%loop% (
	set /a "loops+=1"
	for /l %%i in (0,1,%string.length%) do (
	
		if "!chr[%%i].freeze!" neq "True" (
            set /a "rndchr=!random! %% 86"
            for %%r in (!rndchr!) do (
                set "scrn.string=!scrn.string!!ascii_str:~%%r,1!"
                if "!ascii_str:~%%r,1!" equ "!chr[%%i].ch!" (
                    set "chr[%%i].freeze=True"
                    set /a "frozen+=1"
                )
            )
        ) else (
            set "scrn.string=!scrn.string!!chr[%%i].ch!"
        )
	)
	if !loops! geq 100 set "scrn.string=!string!" & set "frozen=50"
	
	echo [2J%HUD%[48;2;!fade!;!fade!;!fade!;38;5;16m[!map.y!;!map.x!H!lastscrn!%TOP%%cornice%[38;5;!hue!m[%~3;%~2H!scrn.string![0m
	set "scrn.string="
	
	if !frozen! gtr %string.length% (
		goto :eof
	)
)

miskox
Posts: 670
Joined: 28 Jun 2010 03:46

Re: Ghost-typer effect in batch: Flickering random letters before each character

#4 Post by miskox » 18 Aug 2025 08:18

@icarus: can't get it to work. Looks like your ESC is encoded in the file which I can't copy/paste. Please use variable ESC:

Aacini's:

Code: Select all

for /f %%a in ('echo prompt $E^| cmd') do set "ESC=%%a"

Code: Select all

echo [2J
should probably be

Code: Select all

echo %esc%[2J
etc.

Saso

T3RRY
Posts: 258
Joined: 06 May 2020 10:14

Re: Ghost-typer effect in batch: Flickering random letters before each character

#5 Post by T3RRY » 31 Aug 2025 00:14

A modification of Icarus' base script to achieve the desired output style

Code: Select all

@echo off

%= usage example. Outputs requirements if no args =%
	call :animated_string "%~1"    %~2 %~3 %~4

exit /b 0


:animated_string
  If "%~1" == "" cls
  Set "fontSize=18"
  Set "fontType=Lucida Console"
  if not defined SetFont.init Call:Setfont %FontSize% "%fontType%"

set "string=%~1"
setlocal enableDelayedExpansion
If defined string Set "string=!String:{Your String}="Your String"!"
If not defined string (
  Endlocal
  %~f0 "Argument 1 is required when calling %0 IE:" 2 1 81
  %~f0 "Call%0 {Your String} yPos xPos Color" 3 1 32
  Pause
  Exit /b 0
)

For /f %%e in ('echo prompt $E^|%comspec%')Do set \e=%%e
set /a "string.length=0","base.i=6"
if "%~4" neq "" ( set "hue=%~4" ) else ( set "hue=15" )
set "ascii_str= #$'*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]_`abcdefghijklmnopqrstuvwxyz{}~"

Set "while=Set end.while=& For /l %%_ in (1 1 16) do if not defined end.while For /l %%_ in (1 1 16) do if not defined end.while For /l %%_ in (1 1 16) do if not defined end.while For /l %%_ in (1 1 16) do if not defined end.while"

for /l %%b in (8,-1,0) do (
	set /a "string.length|=1<<%%b"
	for %%c in (!string.length!) do if "!string:~%%c,1!" equ "" set /a "string.length&=~1<<%%b"
)
Set /a string.length+=1

Set "outstring="
For /l %%l in (0 1 %string.length%)Do (
  for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100"
  %while% (
    for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do ^
set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, tDiff=t2-t1",^
       "interval=!random! %% !base.i! + (!random! %% !base.i!) + (!random! %% (!base.i!+1))  + (!random! %% (!base.i!)+1) + (base.i-1)",^
       "rndchr=!random! %% 86","offset=%%l-1"
    for /f "tokens=1,2" %%r in ("!rndchr! !offset!") do (
      If %%l GTR 0 (
        Set "outstring=!string:~0,%%s!!ascii_str:~%%r,1!"
      )Else Set "outstring=!ascii_str:~%%r,1!"
      If !tDiff! GTR !interval! (
        Set "outstring=!string:~0,%%l!"
        Set "end.while=1"
      )
      <nul set /p "=%\e%[38;5;!hue!m%\e%[%~2;%~3H!outstring!%\e%[0m%\e%[K%\e%[B%\e%[%%lG"
    )
  )
)
Echo(
ENDLOCAL & Exit /b 0


:setFont <integerSize> <stringFontName>
REM from the StdLibrary created by IcarusLives
REM https://github.com/IcarusLivesHF/Windows-Batch-Library/tree/8812670566744d2ee14a9a68a06be333a27488cc
if "%~2" equ "" goto :eof
call :init_setfont
If not errorlevel 1 Set "SetFont.init=1"
If defined SetFont.init %setFont% %~1 %~2
goto :eof

:init_setfont DON'T CALL
:: - BRIEF -
::  Get or set the console font size and font name.
:: - SYNTAX -
::  %setfont% [fontSize [fontName]]
::    fontSize   Size of the font. (Can be 0 to preserve the size.)
::    fontName   Name of the font. (Can be omitted to preserve the name.)
:: - EXAMPLES -
::  Output the current console font size and font name:
::    %setfont%
::  Set the console font size to 14 and the font name to Lucida Console:
::    %setfont% 14 Lucida Console
setlocal DisableDelayedExpansion
set setfont=for /l %%# in (1 1 2) do if %%#==2 (^
%=% for /f "tokens=1,2*" %%- in ("? ^^!arg^^!") do endlocal^&powershell.exe -nop -ep Bypass -c ^"Add-Type '^
%===% using System;^
%===% using System.Runtime.InteropServices;^
%===% [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] public struct FontInfo{^
%=====% public int objSize;^
%=====% public int nFont;^
%=====% public short fontSizeX;^
%=====% public short fontSizeY;^
%=====% public int fontFamily;^
%=====% public int fontWeight;^
%=====% [MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)] public string faceName;}^
%===% public class WApi{^
%=====% [DllImport(\"kernel32.dll\")] public static extern IntPtr CreateFile(string name,int acc,int share,IntPtr sec,int how,int flags,IntPtr tmplt);^
%=====% [DllImport(\"kernel32.dll\")] public static extern void GetCurrentConsoleFontEx(IntPtr hOut,int maxWnd,ref FontInfo info);^
%=====% [DllImport(\"kernel32.dll\")] public static extern void SetCurrentConsoleFontEx(IntPtr hOut,int maxWnd,ref FontInfo info);^
%=====% [DllImport(\"kernel32.dll\")] public static extern void CloseHandle(IntPtr handle);}';^
%=% $hOut=[WApi]::CreateFile('CONOUT$',-1073741824,2,[IntPtr]::Zero,3,0,[IntPtr]::Zero);^
%=% $fInf=New-Object FontInfo;^
%=% $fInf.objSize=84;^
%=% [WApi]::GetCurrentConsoleFontEx($hOut,0,[ref]$fInf);^
%=% If('%%~.'){^
%===% $fInf.nFont=0; $fInf.fontSizeX=0; $fInf.fontFamily=0; $fInf.fontWeight=0;^
%===% If([Int16]'%%~.' -gt 0){$fInf.fontSizeY=[Int16]'%%~.'}^
%===% If('%%~/'){$fInf.faceName='%%~/'}^
%===% [WApi]::SetCurrentConsoleFontEx($hOut,0,[ref]$fInf);}^
%=% Else{(''+$fInf.fontSizeY+' '+$fInf.faceName)}^
%=% [WApi]::CloseHandle($hOut);^") else setlocal EnableDelayedExpansion^&set arg=
endlocal &set "setfont=%setfont%"
if !!# neq # set "setfont=%setfont:^^!=!%"
exit /b %errorlevel%


Post Reply