Start page: ARABART home
← All fifteen programs

Port Said IT Department

1991 · C:\SCREEN\SCREEN.COM

C:\SCREEN\SCREEN.COM
Port Said IT Department running in DOS

Loading SCREEN.COM, 2 KB

Click the screen to type into the program.

The screensaver for Port Said Governorate's IT department: 156 bytes of code, shorter than a tweet, that play a drawing script.

The story

Yasser did not ship a picture. He wrote a player of just 156 bytes and a script of pen strokes for it, so the whole program is 1,672 bytes on disk. It ran on every computer in the Port Said Governorate's computer department, where he was an intern. The same year he used that player again, for a doctor's calligraphy splash and a 15-picture advertisement.

A screen that draws itself

In 1991, as an intern in the computer department of the Port Said Governorate, Yasser gave the department a screen of its own. It shipped as 156 bytes of code that draw it, one short pen stroke at a time.

The three lines read محافظة بورسعيد, مركز المعلومات و التوثيق and إدارة الحاسب الآلى: Port Said Governorate, Information and Documentation Center, Computer Department. It ran on every computer in the department. Below is his real file, played by a line-for-line JavaScript copy of his player. The first line is gray with a red shadow, the second is yellow, and the third keeps changing color until someone presses a key.

C:\SCREEN\SCREEN.COM
His screen: محافظة بورسعيد, مركز المعلومات و التوثيق and إدارة الحاسب الآلى in three lines, red, yellow and cyan, on black.

Three lines, 1,135 strokes, drawn by 156 bytes of code.

Press a key and the screen says goodbye in text: K E M Y A M Software Corp., <C>1991 YASSER MOHAMED ALI. KEMYAM is the name he signed his 1991 work with.

156 bytes

The whole program is 1,672 bytes on disk. The same screen as a plain picture would take 112,000.

A picture file stores every pixel: 640 by 350 of them, half a byte each for 16 colors. Yasser stored the drawing instead. His script says where each stroke of each letter goes, and a tiny player follows it. Think of an SVG next to a PNG: instructions for drawing, not the pixels themselves.

Then he packed the file with DIET, a compressor for programs, the way a build step minifies and gzips a JavaScript bundle. Tap any bar to measure the others in it.

SCREEN.COM, to scale

Sizes in units of his player: all the code that draws. Tap any bar to make it the unit.

Two bytes, one stroke

A stroke is two bytes: how far down it starts, and how many pixels it runs. The letter x moves the pen one column to the left.

Every letter on the screen is a row of thin vertical strokes, like a brush pulled down the page column by column. His player reads the script one byte at a time. A byte below 70h starts a stroke. The letters x, w, y and { are commands: left, right, new line, end of the picture.

Each pixel goes through the BIOS, the drawing service built into every PC, like calling a browser API instead of talking to the graphics card. Right after it, the same pixel is drawn again 2 to the right and 2 down in the shadow color. That second pixel gives every letter its carved, raised look. Step through the start of the first letter, م.

MEMORY the first bytes of the script
  1. 4B
  2. 43
  3. 00
  4. 07
  5. 04
  6. 40
  7. 00
  8. BD
  9. 01
  10. 20
  11. 04
  12. 78
  13. 1F
  14. 06
  15. 78
  16. 1E
  17. 08
  18. 78
  19. 1D
  20. 04
  21. 23
  22. 04
  23. 78
  24. 1C
  25. 04
  26. 23
  27. 04
  28. 78
  29. 1C
  30. 04
  31. 22
  32. 04
  33. 78

4B header 40 origin: row 64, column 445 78 x

ZOOM ×20
SCREEN.COM the drawing loop
  1. 012Enext:mov dl,[si]; read a byte
  2. 0130inc si
  3. 0131cmp dl,70h; under 70h:
  4. 0134jl stroke; a stroke
  5. 0136cmp dl,'x'; x: one column
  6. 0139jne 013Eh
  7. 013Bdec bx; left (header)
  8. 013Cjmp next
  9. 013Ecmp dl,'w'; w: the other way
  10. 0143inc bx; right (header)
  11. 0146cmp dl,'y'; y: a new line
  12. 014Bcmp dl,'{'; {: picture done
  13. 016Fstroke:mov dh,0; DX = the byte
  14. 0171add dx,di; row = top + byte
  15. 0173mov cl,[si]; the length
  16. 0175inc si
  17. 0178pixel:mov ax,0C07h; gray (header)
  18. 017Bxchg bx,cx; column to CX
  19. 017Dint 10h; BIOS: a pixel
  20. 017Fjmp 0181h; shadow on (header)
  21. 0181mov ax,0C04h; red (header)
  22. 0184inc cx / inc cx; 2 right
  23. 0186inc dx / inc dx; 2 down
  24. 0188int 10h; the shadow
  25. 018Adec cx / dec cx; back
  26. 018Cdec dx / dec dx
  27. 018Einc dx; next row
  28. 018Fxchg bx,cx; count to CX
  29. 0191loop pixel; until done
  30. 0193jmp next
The same in C
  1. for (;;) {
  2. op = *s++;// next byte
  3. if (op == 'x') col--;// or ++
  4. else if (op == 'w') col++;
  5. else if (op == 'y') header();
  6. else if (op == '{') frame();
  7. else {// a stroke
  8. row = top + op;
  9. n = *s++;// length
  10. while (n--) {
  11. plot(col, row, ink);
  12. if (shadow)
  13. plot(col+2, row+2, shade);
  14. row++;
  15. }
  16. }
  17. }
Watches
SI
byte 25 where it reads next
DL
78h the letter x
BX
439 the pen: column
DX
102 the pen: row
CX
0 pixels left in this stroke
Help

dec bx: the pen moves one column left, to 439. Arabic runs right to left, and so does his pen.

The pen moves left 937 times and right 24 times across the three lines. Stepping back to the right lets a new letter tuck in over the one before it, the way Arabic letters overlap. 1,135 strokes in all, and not one stored pixel.

Five bytes rewrite the code

Each line starts with five bytes. His player copies them straight into its own instructions, so one tiny loop draws every style on the screen.

The ink color is not a variable the loop looks up. It is part of the instruction itself, mov ax,0C07h, and the header writes the 07. The shadow switch is the jump right after the pixel. A jump of 00 runs into the shadow code, and 0D jumps past it. Even the direction is a byte: 4B is the instruction “one column left”, 43 is “one column right”. This is self-modifying code, used as settings. Change the header and watch his player draw line 1 again.

HEADER line 1
Ink
Shadow
Shadow color
The pen moves
SCREEN line 1
محافظة بورسعيد, Port Said Governorate, in gray with a red shadow.
SCREEN.COM after reading the header

The script's first 9 bytes

  1. 4B
  2. 43
  3. 00
  4. 07
  5. 04
  6. 40
  7. 00
  8. BD
  9. 01

The 5 places in his code they go

  1. 013B4Bdec bxx: one column left
  2. 014343inc bxw: one column right
  3. 017FEB 00jmp 0181hinto the shadow code
  4. 0178B8 07 0Cmov ax,0C07hink: light gray
  5. 0181B8 04 0Cmov ax,0C04hshadow: red

Header 4B 43 00 07 04: his own line 1. Change any of it and his player draws the line again.

His three lines use three headers: 4B 43 00 07 04 gray with a red shadow, 4B 43 0D 0E 0E yellow with no shadow, and 4B 43 0D 03 0E cyan with no shadow. Today a game sets a shader's uniforms before each draw call in the same spirit: one routine, a few values changed per line.

Always moving

When the picture is done, he asks DOS if a key is waiting. If not, he adds 1 to the color byte inside his own code and draws line 3 again.

One byte inside his plot instruction holds the color, the 03 of mov ax,0C03h. So one inc recolors the whole line on its next pass. It counts up to 15, then starts again at 2, so line 3 never turns black. The whole animation is the short listing below. Scrub through the 14 colors, or run them.

SCREEN line 3
إدارة الحاسب الآلى, Computer Department, in cyan.
SCREEN.COM 014B
  1. 014Bcmp dl,'{'end of the picture
  2. 0150mov si,0A9Bhline 3's start
  3. 0153mov ax,0B00hDOS: a key waiting?
  4. 0156int 21h
  5. 0158cmp al,0FFhyes: stop
  6. 015Cinc byte [0179h]no: next ink
  7. 0160cmp byte [0179h],10hpast 15?
  8. 0167mov byte [0179h],2back to 2
  9. 016Djmp 0126hdraw again

0179h, inside mov ax,0C03h, now holds 03h: cyan

On the real screen the new color sweeps across the line from right to left as the pen redraws it. That is why the screenshot at the top of the page catches line 3 in two colors at once. The keyboard check is one question to DOS, “is a key waiting?”, the same question a game loop asks between frames.

Write your own

His script is plain bytes, so anyone can write one. This editor turns your words into the exact bytes his player reads, and his player draws them as you type.

SCRIPT.TXT one column per line

17 strokes, 56 bytes. His player draws them as you type.

SCREEN zoomed to fit
The first letter of his first line, م, drawn by his player in gray with a red shadow.
AS BYTES what his player reads
  1. 4B
  2. 43
  3. 00
  4. 07
  5. 04
  6. 40
  7. 00
  8. BD
  9. 01
  10. 20
  11. 04
  12. 78
  13. 1F
  14. 06
  15. 78
  16. 1E
  17. 08
  18. 78
  19. 1D
  20. 04
  21. 23
  22. 04
  23. 78
  24. 1C
  25. 04
  26. 23
  27. 04
  28. 78
  29. 1C
  30. 04
  31. 22
  32. 04
  33. 78
  34. 1D
  35. 04
  36. 22
  37. 04
  38. 78
  39. 1E
  40. 07
  41. 78
  42. 1F
  43. 06
  44. 78
  45. 20
  46. 04
  47. 78
  48. 21
  49. 04
  50. 78
  51. 22
  52. 04
  53. 78
  54. 23
  55. 04
  56. 78

Try changing one length in his letter, or add a y and a second line. Every line here uses his line 1 header: gray ink, red shadow, the pen moving left from column 445.

One player, three programs

He kept this player and used it twice more in 1991. One is TAHER.COM, the calligraphy splash for a physician. The other is the 15-slide advertisement for a Port Said computer center. Those two share their first 241 bytes, and the player in them learned two new words: one to clear the screen for the next picture, one to end the show.

Then and now
1991 to 19932026Why it is the same idea
A screen stored as drawing commands, played by a 156-byte player An SVG, or a Lottie animation played by a small runtime The file says how to draw, not every pixel, so it stays tiny.
Strokes: a start and a length in each column Run-length encoding in fax images and TIFF A long run of ink costs two bytes, however long it is.
Header bytes written into the drawing loop Shader uniforms set before a draw call One routine draws every style; a few values change per line.
One player, three programs A game engine that loads level files Write the engine once, ship new work as data.
For engineers: the start and the header reader
SCREEN.COM 0100 to 012D
0100 mov si,019Ch ; the script starts right after the code
0103 mov ax,10h / int 10h ; EGA graphics, 640 by 350, 16 colors
0108 mov al,[si] / inc si / mov [013Bh],al ; the opcode for 'x'
010E mov al,[si] / inc si / mov [0143h],al ; the opcode for 'w'
0114 mov al,[si] / inc si / mov [0180h],al ; the shadow jump
011A mov al,[si] / inc si / mov [0179h],al ; the ink color
0120 mov al,[si] / inc si / mov [0182h],al ; the shadow color
0126 mov di,[si] / inc si / inc si ; the line top, in rows
012A mov bx,[si] / inc si / inc si ; the starting column
The program is a .COM file, loaded at 0100h. The script begins at 019Ch, 156 bytes in.

It sets EGA mode 10h through INT 10h and plots with the same service, function 0Ch. A key ends it: text mode, then DOS prints his credit with function 09h, which reads up to a $.

Every Byte of SCREEN.COM

Each square is one byte of the program in memory, colored by what it is. Tap a part to open it in the full map, down to the single instruction.

C:\SCREEN\SCREEN.COM