Remember the roaring 80's? I mean, you know, like 30 years ago? No cell phones, no internet, no ATM's, fluorescent clothing (what was that?!) and scrolling marqee's! No, no, no! Not the online ones, but real ones, With LED lights.

Scrolling marquee

Since I'm in a nostalgic mood, I'd like you to create a scrolling marquee.


Create a program where you can enter a one line string. You program needs to create a 80 character wide scrolling marquee, repeating the text if necessary.


  • The user must be able to enter a string to your program as input. The string can be a command line parameter or a string entered while running the program.
  • Your program must continuously print a string of exactly 80 (visible) characters.
  • The string must be updated every 0.1 second (more or less; I won't be timing it), shifting the characters every iteration one position to the left.
  • The string "rotates". At the end of the user supplied string, another instance of the string must appear.
  • You program must print it's output on one line, without linefeeds (use a '\r' instead of a '\n')
  • Your program must run ad infinitum, until an user interrupt.
  • This is a codegolf, so shortest code in bytes wins.
  • There is a 10% bonus (rounded up to the next integer) for printing in red on a black background.
  • Standard loopholes apply.

Reference implementation in Python 2.7

This program isn't golfed, but it provides a reference implementation (and thus an upper limit to the size).

import time,sys
while 1:
    for i in range(80):
        print s[i:i+80]+'\r',
  • \$\begingroup\$ @mbomb007 similar, but not the same. Also this question looks like it (good for inspiration) but it is different on several respects, I think. Also, I found the scores (code lengths) quite disappointing. I really think we can do better! \$\endgroup\$
    – agtoever
    Commented Sep 25, 2015 at 18:12
  • \$\begingroup\$ Maybe as code golf + popularity contest? \$\endgroup\$ Commented Sep 25, 2015 at 19:09
  • \$\begingroup\$ Do we have to wait exactly 100 ms? \$\endgroup\$
    – Dennis
    Commented Sep 26, 2015 at 6:24
  • 1
    \$\begingroup\$ @Dennis well, more or less. It's ok if you set it to 99 to save a char. Let's say the execution of the other instructions will take 0.01 sec. :-) \$\endgroup\$
    – agtoever
    Commented Sep 26, 2015 at 6:28
  • 1
    \$\begingroup\$ What should happen if the input string is more than 80 characters? Your reference implementation, and my answer, get to s[80:160] and then jump back to s[0..] they never print the end of the long string, e.g. an input of 1 2 3 4 5 6 7 8 9 10 11 ... 300 cuts off after about 56. \$\endgroup\$ Commented Sep 26, 2015 at 20:54

27 Answers 27


PowerShell, 118 113 112 108 102 101 99 96 - 10% = 86


$s=(Read-Host)*180;for(){Write-Host($s.substring(($i=++$i%80),80)+"`r")-N -F R -B 0;sleep -m 99}

With the caveat that it now begins the first loop with the second character; The rules don't say it has to start from the front of the string, and the first one is included overall, so that's fine by me. I will get it to 100 chars somehow - edit: thanks @ConnorLSW for the edits to get it below 100.


  1. Run PowerShell (normal console, it doesn't work in PowerShell ISE)
  2. Paste the single line version into PoSH, press enter
  3. Type a message, press enter
  4. Ctrl-C to break


PowerShell marquee example output


A more readable version with the variable names and parameters filled out a bit:

$test = (Read-Host) * 180
for () {
    Write-Host ($text.substring(($i=++$i%80), 80)+"`r") -NoNewLine -ForegroundColor Red -BackgroundColor Black
    sleep -Miliseconds 99
  • The parameters only need to be long enough to be unique, so -F R is unique enough to set a Red ForegroundColor, for example.
  • 'Black' has to be 'Bla' to be unique compared to 'Blue', but -B 0 sets it to color Enum value 0 which is interpreted as Black.

Alternative, more 'correct' marquee:

The reference code doesn't handle strings longer than 80 characters nicely, skipping anything in the message past ~160 characters, and it glitch-resets every 99*len(string) characters. e.g. if the sign width was 5 characters long, it does this:

   here is my long test input
 0 |here |            
 1  |ere i|          ^^^^ never shown
 2   |re is|
 3    |e is |
 4     | is m|
 0 |here |
 1  |ere i|

This version indexes modulo the text length instead of the sign width, so it runs through the whole string. 106 - 10% = 95 chars.

$l=($s=Read-Host).Length;for(){Write-Host(($s*160).substring(($i=++$i%$l),80)+"`r")-N -F R -B 0;sleep -m 99}

Alternative: sign which cycles like the .gif in the question, 118-10%=106

Because it looks better.

$s=' '*80+(read-host)+' '*80;for(){write-host($s.Substring(($i=++$i%($s.length-80)),80)+"`r")-N -F R -B 0;sleep -m 99}

Alternative sign example animation

  • 1
    \$\begingroup\$ I know this answer is pretty old, but this question is frontpage right now - Bla to 0 - Write-Host will interpret numbers to colors. \$\endgroup\$
    – colsw
    Commented Feb 16, 2017 at 11:08
  • \$\begingroup\$ @ConnorLSW Thanks, you got it below 100 chars! And I have no idea why I missed your comment a year ago(!) someone just upvoted and I came back to see what it was. \$\endgroup\$ Commented Feb 23, 2017 at 19:10
  • \$\begingroup\$ no worries, I think you can also change while(1) to for() to save some bytes :) \$\endgroup\$
    – colsw
    Commented Feb 23, 2017 at 20:10
  • \$\begingroup\$ @ConnorLSW so you can, done that too. (I could probably do that in most of my golfs, it's not something I think of normally). \$\endgroup\$ Commented Feb 23, 2017 at 20:30
  • \$\begingroup\$ As you're using for(), you can save one more byte changing $s=(Read-Host)*180;for(){ to for($s=(Read-Host)*180){ \$\endgroup\$
    – Clijsters
    Commented Nov 15, 2017 at 15:06

Matlab, 76 bytes

What I think is nice here is that you can have vectors as array indices. This returns a vector of the corresponding array entries, which makes it very easy to append the given string independently of the length.

a=input('');k=1:80;while 1;pause(.1);clc;k=mod(k+1,nnz(a));disp(a(k+1));end


enter image description here

  • \$\begingroup\$ Nice trick with clc. You forgot to add 's' in input \$\endgroup\$
    – Luis Mendo
    Commented Sep 26, 2015 at 11:38
  • \$\begingroup\$ What s do you mean? It works perfectly fine as it is in the Matlab version I have acces to (R2010b). \$\endgroup\$
    – flawr
    Commented Sep 26, 2015 at 12:04
  • 1
    \$\begingroup\$ As it is now, you need to input the string with quotes. To enter the string contents directly (without qoutes) you need a=input('','s') \$\endgroup\$
    – Luis Mendo
    Commented Sep 26, 2015 at 12:46
  • \$\begingroup\$ Now I see, I was not aware of that feature. As the specs do not require this, I think it is ok to require ' delimited strings as input. Many languages need a string delimiter or they would interpret a command line argument in the form of a sentence (words separated by spaces) as multiple arguments anyway. \$\endgroup\$
    – flawr
    Commented Sep 26, 2015 at 13:02

CJam, 31 bytes


Waits for exactly 100 ms.

This will only work with the official Java interpreter, since the online interpreter only shows output after exiting the program.

Red text on black background is possible in 40 (or 39) bytes, for a score of 36:

0000000: 6c 38 30 2a 7b 22 0d 1b 5b 33 31 3b 34 30 6d 22 6f 5f  l80*{"..[31;40m"o_
0000012: 38 30 3c 6f 28 2b 65 73 39 39 2b 7b 65 73 31 24 3c 7d  80<o(+es99+{es1$<}
0000024: 67 3b 7d 68                                            g;}h

How it works

l80*                             Read a line and repeat it 80 times.
    {                        }h  Do:
     Dco                           Print the character with code point 13.
        _80<o                      Print the first 80 characters of the string.
             (+                    Rotate the string one charcter to the left.
               es99+               Push the current time (ms) plus 99.
                    {     }g       Do:
                     es1$<           Compare the current time with the sum.
                                     Repeat the loop if 99 or less ms have passed.
                            ;      Discard the time stamp.
                                 Repeat the loop.
  • \$\begingroup\$ I suspect they won't come shorter than this. Congratulations! \$\endgroup\$
    – agtoever
    Commented Oct 4, 2015 at 15:02
  • \$\begingroup\$ Seems tlike the ; in the explanation is misaligned \$\endgroup\$
    – Ven
    Commented Feb 23, 2017 at 12:14
  • \$\begingroup\$ @Ven Fixed, Thanks! \$\endgroup\$
    – Dennis
    Commented Feb 23, 2017 at 13:50

QBasic, 116 113 bytes - 10% = 105 102

FOR i=a TO a+79
?MID$(s$,i MOD LEN(s$)+1,1);
2ON(TIMER<t)+2GOTO 2,1

Marquee demonstration

Here's a formatted version with some comments:

COLOR 4   ' 4 is the color code for red (the background's already black)

1 CLS   ' CLear Screen (and mark this as line number 1)

' The variable a represents an offset from the beginning of the string
' As a numeric variable, it is 0 at the beginning of the program
FOR i = a TO a + 79
    ' Print i'th character mod string length (+ 1 because QBasic strings
    ' are 1-indexed)
    PRINT MID$(s$, i MOD LEN(s$) + 1, 1);
a = a + 1

' Do a busy-wait for .1 seconds
' (Unfortunately, QBasic's SLEEP command only takes integer values)
' Set t to the time we want to stop waiting, .1 seconds in the future
t = TIMER + .1
' We want to stay on line number 2 while TIMER < t; once that condition is
' no longer true, we want to goto the top of the outer loop (line number 1)
' Since true is -1 and false is 0 in QBasic, adding 2 to the conditional
' gives 1 for true and 2 for false; we can pass these values to the
' ON ... GOTO statement to branch conditionally
2 ON (TIMER < t) + 2 GOTO 2, 1

A couple of notes:

  • I don't know why the PRINT after the FOR loop is necessary. CLS should reset the cursor to the top left corner each time. But on QB64, at least, if I don't put the extra PRINT in, the marquee ends up on the second line instead of the first. If anybody has QBasic set up on DosBox or somesuch, I'd be interested to know if the same thing happens there or if it's a QB64 bug.
  • The code has a small glitch because it relies on TIMER (number of seconds since midnight) for the delay. If the code is running at midnight, the marquee will get stuck because TIMER will reset to 0 and always be less than t thereafter.
  • \$\begingroup\$ My first language! IIRC, in QB 4.5 anyway, a semicolon at the end of a printed string means the PRINT statement does not print a carriage return. \$\endgroup\$
    – bgStack15
    Commented Sep 15, 2016 at 11:59
  • \$\begingroup\$ @bgStack15 Mine too. :^D The issue isn't really with PRINT but with CLS--after CLS, no matter what was printed before, the next PRINT statement should output at 1,1; but instead, I ran into a situation where it output at 2,1. \$\endgroup\$
    – DLosc
    Commented Sep 15, 2016 at 18:25

Perl, 99 98 bytes (-10% = 89)

$|=@_=split('',pop);printf("\e[31m\r%.80s",join('',@_)x80)while select($a,$a,$a,.1)|push@_,shift@_

Takes its input from command line parameter.

perl marquee.pl "Welcome to Programming Puzzles & Code Golf "

pb, ⌈(216 + 3)*0.9⌉ = 198

+3 bytes for interpreter flag d=1


A pretty horrible score, but considering how hard it is to do anything in this language it could be worse. This answer's ratio of (bytes used to get red text) to (bonus from having red text) is really good, the whole output is turned red with only the c at the beginning!

The time between each tick varies depending on the length of the input string but it's around 0.1 seconds.

By the way, this program's output looks like total garbage because the interpreter is so bad. Every millisecond it clears the terminal and redraws everything, so it gets really flickery.

With comments:

c           # Change paint colour to red

^w[Y=-1]{   # While Y=-1 (arbitrary condition we can break later)

    w[B!0]{>}   # Go to end of input

    t[X]        # Save length of input in T

    # SET T TO MAX(T-79, 0)

    <[X-79]     # Go to (79, -1)

    w[X!0]{     # While X is not 0
        t[T-1]      # Subtract 1 from T
        w[T=-1]{    # If T is now negative
            t[0]        # Set it back to 0
        <         # Move left (position doesn't matter except to end the loop eventually)

    # DONE SETTING T TO MAX(T-79, 0)
    # If T == 0, the string needs to be doubled. Otherwise this part of the program is done

    v           # Move down to break the loop unless this is specifically undone
    w[T=0]{     # While T == 0
        ^w[B!0]{    # For each byte of input
            t[B]^b[T] # Copy it up 1 place
            >v        # Go to the next byte
        <[X]^     # First byte of the copy
        w[B!0]{   # For each byte of the copy
            t[B]      # Save the byte's value
            vw[B!0]{>}# Go to the first empty spot after the original
            b[T]      # Write the saved value
            <[X]^w[B=0]{>} # Go back to the first byte of the copy
            b[0]>     # Erase it and go to the next one
        v       # Back to Y=-1 to reset the loop from the very beginning


# After ALL OF THAT nonsense, we're now at (0, 0) and the input string is guaranteed to be
# at least 80 characters long

w[1=1]{       # While 1=1 (should hold true until mathematics itself breaks down)
    <[X-80]        # Go to the 81st character
    w[X!0]{        # While X!=0
        <t[B]vb[T]^    # Go left and copy that character down

    w[B!0]{      # For each byte in the string
        t[B]<b[T]>>  # Copy that byte left

    <[X]<t[B]    # Go get the first value (copied to (-1, -1))
    w[B!0]{>}<b[T]# Bring it to the end of the string

Perl - 120 bytes (-10% = 108)

$|=1;$_=<>;chomp;for(;;){print "\e[31m",substr(" "x80 .$_,$p++,80)," \r";select($z,$z,$z,0.1);if($p>length()+80){$p=0}}

Perl marquee


Matlab, ⌈188*.9⌉ = 170

This works in Matlab version R2014b or higher. The result is shown on a figure window.

h=text(.1,.1,repmat(' ',1,80),'fontn','courier','ba','k','co','r');set(1,'pos',[90 90 990 90]);axis off
s=input('','s');n=0;while 1

In the following example, text is typed in boldface for better visualization (not done in the above code because it costs a few bytes). Note also that the speed of the GIF animation does not correspond to the required 0.1 s pause, but the timing is correct in the actual figure shown by running the program.

enter image description here


SpecBAS, 130 bytes (-10% = 117)

Multiplies the original string to make it 80 or more characters, then chops it to exactly 80.

TEXT is a command in SpecBAS that works the same way as PRINT (in this example) but saves one character.

The SCALE command adds a few extra characters to the code, but makes it look more marquee-ish.

The program keeps going until you press Esc.

1 INPUT s$: LET s$=s$*CEIL(80/LEN s$)
2 TEXT PAPER 0;INK 2;SCALE 1,2;AT 1,1;s$( TO 80)
3 LET s$=s$(2 TO)+s$(1): PAUSE 5: GO TO 2

enter image description here


Perl, 63 (70 chars - 10% for bonus)

Not a hugely different solution to the others, but I wasted my time making it, so I thought I'd post it as well!

/ /;print"\x0d\x1b[91m",substr"$_"x80,$z++%y///c,80 until`sleep .1`

Relies on a Unix-compatible terminal for ANSI codes and the call to coreutils' sleep. The two \x.. chars in the above are actually a literal line-feed and escape char as per this hex dump:

0000000: 245f 3d3c 3e3b 732f 0a2f 202f 3b70 7269  $_=<>;s/./ /;pri
0000010: 6e74 220d 1b5b 3931 6d22 2c73 7562 7374  nt"..[91m",subst
0000020: 7222 245f 2278 3830 2c24 7a2b 2b25 792f  r"$_"x80,$z++%y/
0000030: 2f2f 632c 3830 2075 6e74 696c 6073 6c65  //c,80 until`sle
0000040: 6570 202e 3160                           ep .1`

Ruby, 79 76 75 bytes

sleep 0.1}

I'm still not a ruby expert, possibly can be golfed down.

With red & black same score:

loop{system'cls&color 4'
sleep 0.1}

Perl, 84 bytes (- 10% = 76)

$_=' 'x80 .pop;$|=print"\b \r\e[31m".substr$_,++$p% length,80until select$z,$z,$z,.1

This takes a command line argument which is the text in the marquee.


  1. Prepend 80 spaces to the text and store in $_
  2. Print backspace (\b) and a space ( ). This removes the last character from the previous print. Then print the carriage return and colour.
  3. Print the 80 characters of the text from position $p
  4. $p = ($p+1) % length of text
  5. Sleep for 0.1 secs

bash, 121 bytes

A=$(printf ' %.s' {1..80})$1
while :; do
printf "%s \r" "${A:((P++)):80}"
if [ $P == ${#A} ];then
sleep 0.1

Japt, 12 bytes

Outputs an integer before starting into the marquee.


Try it

But, if that's not valid then ...

Japt, 14 bytes

Oq80îUéV´ Lt@ß

Try it

Oq80îUéV´ Lt@ß     :Implicit input of string U
Oq                 :Overwrite output with
  80î              :  Mould the following to length 80
     Ué            :    Rotate U right this many times
       V           :      Second input variable, defaulting to 0
        ´          :      Postfix decerement
          L        :100
           t       :Set timeout for L milliseconds to
            @      :  Run this function
             ß     :    Recursive call with implicit arguments U & (now decremented) V

Python 3, 96 bytes

import time;s=input()*80
while 1:print("\033[2J",end=s[:80],flush=1);s=s[1:]+s[0];time.sleep(.1)

This will only work on terminals that support ANSI escape sequences. If you are on Windows, try ansicon.

Hurrah for the flush keyword in Python 3, so we don't have to make an expensive sys.stdout.flush() call.


C, 293 269 bytes

(Newlines added for readability)

This takes input from standard input terminated by EOF; so it's best to enter a string, a newline, and then the EOF (e.g., Ctrl^D).

#define Z '\0'
main(){int i=0,j;char m[80],o[80],n[2];


#include <stdio.h>
#include <string.h>
#define ANSI_COLOR_SET "\x1b[40;31m"
#define ANSI_COLOR_RESET "\x1b[0m"

int main(void)
  int i, j, c;
  char msg[80], out[80], next[2];

  for (i = 0; (c = getchar()) != EOF && i < 80; ++i) {
    if (c != '\n') {
      msg[i] = c;
  msg[i - 1] = '\0';

  while (1) {
    for (i = 0; msg[i] != '\0'; ++i) {
      strcpy(out, &msg[i]);
      for (j = 0; j < i; ++j) {
        next[0] = msg[j];
        next[1] = '\0';
        strcat(out, next);
      printf(ANSI_COLOR_SET "%s\r" ANSI_COLOR_RESET, out);

SmileBASIC BIG, 79 bytes

FOR I=0TO 79?S$[(I+O)MOD LEN(S$)];

I had a nice graphical solution almost done when I realized it has to scroll 1 whole character at a time.


Jelly, 20 19 18 bytes

  • -1 byte by replacing the first 80 by (= 256) because it has to be multiplied by at least 80
  • -1 byte by changing infinite loop to Çß (from Ç1¿).


With some tricks from @Dennis' answer here. Jelly is newer than the challenge, but not really specifically tailored for it. Suggestions on how to improve are welcome! If your console is in utf-8, run export LC_ALL=en_US or similar before trying.




ẋ⁹ḣ80ṙ1;”ÆṄœS.1         Monadic helper link - Argument: s
ẋ⁹                      Repeat s 256 times.
  ḣ80                   Head. Set {output} to first 80 characters from repeated s.
     ṙ1                 Rotate. Rotates {output} one character to the left.
       ;Ӯ              Concatenate character 0D, the carriage return, to {output}.
          Ṅ             Print and return {output}.
           œS.1         Wait 0.1 seconds before returning {output} from the
                        helper link.

Çß                      Monadic main link - Argument: s
Ç                       Execute helper link with argument s. Replace s by
                        result of helper link.
 ß                      Execute this link with argument s (while true).

Uiua, 30 bytes


We can’t just repeat the string to length 80 and rotate that because the text won’t loop around evenly. Instead, I just made it so that it takes 80 copies of the input, separated by spaces, and in each iteration just takes the first 80 characters of that.


LOVE2D Lua, 197-10% = 178 Bytes

f=io.open("t.t"):read().."  "love.graphics.setColor(255,0,0)love.window.setMode(640,14)function love.draw()s=""for i=1,80 do n=i+os.clock()s=s..f:sub(n%#f,n%#f) end love.graphics.print(s,0,0)end

Requires the input to be in a file called 't.t' in the root, thus 3 extra bytes were added to the score.

Really basic in functionality, just in a for loop of 80 iterations, append the character at index of i plus the current time in seconds modulated by the length of the current string, giving a repeated 80 character long string of the input, which shifts left as time goes on.

I used LOVE2D For the laughs.


Sinclair ZX81/Timex TS1000/1500 BASIC, 110 bytes 182 bytes (for the listing)

2 PRINT AT 0,0;A$(1 TO 80)
3 LET A$=A$(2 TO )+A$(1)
4 GOTO 3

It works by printing the first 32 80 characters of the string A$ at screen position 0,0 in line two, and then manipulating the string from position 2 to the end of the sting in line 3 (Sinclair ZX81 BASIC indexes strings from 1 and not zero), therefore adding the first character to the end and passing it back to the A$ variable; then there's a unconditional loop back to line 2.


Commodore 64, 434 bytes

2 POKE53280,6:PRINT"{CLEAR}";
4 FORI=0TO99:NEXT:A$=RIGHT$(A$,142)+LEFT$(A$,1):GOTO3

As this requires 80 characters to show, and the C64 by default is only 40 characters, then 40 characters of the scrolly is printed on the top line of the screen area whilst the other 40 are printed near to the bottom.

To clear up what the {HOME} and other symbols translate into as PETSCII then here is a screen grab taken from my emulator:

Commodore 64 scrolly over two lines

I will do a full golfed-version when I get CBM PRG Studio installed (or when I'm not on lunch at work).


Ruby, 79 77 chars

->(s){t=0;loop{system("clear");puts (s*80)[t..(80+t)];t=(t+1)%80;sleep(0.1)}}

PHP, 136 bytes

while(true){for($i=0;$i<=80;$i++){usleep(100000);echo substr($s,$i)."\r";}}die;
  • Call it with php -f marquee.php hello\ world to marquee "hello world" string.
  • For some reason, I had to do 160 characters for the initial string, else the output would be something like hello worlddddddddddddddddddddddddddddddddddddddd, but it'll only loop through 80 characters - I hope that still counts.


It's been a long day, there's probably something I can do to improve it


PHP, 85 bytes

for(;;usleep(1e5))echo substr(str_repeat($s=$argv[1],80),$i=++$i%strlen($s),80),"\r";

takes input from first command line argument; run with -nr.

Starts scrolling with the second character. Add one byte to start at the first character:
Replace =++$i% with %= and ;; with ;;$i++,.


[Wolfram Language (Mathematica)], 110 bytes

(s=StringPadRight[#,80,#];Monitor[While[True,[email protected];s=StringRotateRight@s],Style[s,Red,Background->Black]])&

It works well with Mathematica desktop, but not with TIO/ATO (
So if someone can make a running string with TIO, it’ll be cool


HTML+CSS+JavaScript, 10+27+80-10% = 106 bytes

<pre id=O>

Takes input with a prompt popup. Updates every 80ms - if that's too fast then it's +1 byte to make it 99ms. A blank input (pressing Cancel when asked for input) causes an error.

Adding the bonus black background and red foreground costs more than it saves, but it seemed like a missed opportunity to not include it.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.