VictorCodebase/

Hex Stream Terminal Docs

v1.0.0

Getting Started with Hex Stream Terminal

Welcome to the Custom Terminal, a fun and extensible Python terminal that accepts both raw hex streams and human-readable string commands. This guide will get you cloned, set up, and sending your first commands.

Hex Stream Terminal banner

A. Overview

The Custom Terminal is a Python-based terminal emulator with two operating modes. It was originally designed to interpret raw hex streams as drawing commands, and has since been extended to also accept human-readable string commands via the --readable flag. Both modes ultimately resolve to the same hex execution pipeline under the hood, ensuring consistent, validated behaviour.

# Hex mode (default)

0x01 0x03 0x50 0x18 0x01 0xFF

# Readable mode (--readable)

screen_setup 80 24 16colors

Both examples above are equivalent: they set up an 80Γ—24 screen in 16-color mode. The terminal translates readable commands into hex before executing them.

B. Prerequisites & Setup

1. Requirements

  • Python 3.8 or higher: Download from python.org.
  • argparse: standard library, included with Python.
  • sys: standard library, included with Python.
  • A terminal emulator: bash, zsh, cmd, or PowerShell.

No pip installs needed

This project uses only Python standard library modules. No pip install step is required. As long as you have Python 3.8+, you're ready to go.

2. Clone the Repository

git clone https://github.com/VictorCodebase/CustomTerminal.git
cd CustomTerminal

That's it. No build step, no virtual environment required. The project runs directly with Python.

C. Running the Terminal

The entry point is terminal.py. Run it with or without the --readable flag depending on which mode you want.

Hex mode (default):

python terminal.py

Human-readable string mode:

python terminal.py --readable

Once running, the terminal will wait for your input. Type a command (or paste a hex stream) and press Enter to execute it.

D. Hex Mode

In hex mode (the default), you input raw hex byte streams separated by spaces or commas. The terminal parses each stream, validates it, and executes the corresponding commands.

Stream Structure

Every valid command stream begins with a command byte (0x01–0x08), followed by the correct number of argument bytes, and ends with 0xFF (end-of-file marker). Multiple commands can be chained in a single input.

Example: set up screen then draw a character:

0x01 0x03 0x50 0x18 0x01 0xFF 0x02 0x04 0x00 0x00 0x07 0x41 0xFF

This sets up an 80Γ—24 screen in 16-color mode, then draws the character A in white at position (0, 0).

E. Understanding the Hex Stream

Every hex stream follows a strict but simple structure. Once you understand the anatomy of a single command stream, you can read and write any input the terminal accepts.

Stream Anatomy

A single command stream is made up of three parts, in order, with the full input terminated by a final 0xFF end-of-file byte:

0x01
Command ID
0x03
Arg Length
0x50
Arg 1
0x18
Arg 2
0x01
Arg 3
↓
next cmd or…
0xFF
End of File

Example: screen_setup 80 24 16colors as a single-command stream

Byte 1 β€” Command ID

Always the first byte in a command stream. Ranges from 0x01 to 0x08, each mapping to one of the eight available commands. The terminal uses this byte to know which command to run and what to expect in the bytes that follow.

0x01screen_setup
0x02draw_char
0x03draw_line
0x04render_text
0x05cursor_move
0x06draw_at_cursor
0x07clear_screen
0x08render
Byte 2 β€” Argument Length

The second byte declares how many instruction bytes follow. The terminal reads exactly this many bytes as the command's arguments, no more and no less. This is how the parser knows where one command ends and the next begins, enabling reliable command chaining.

Some commands have a fixed, strict length requirement (e.g. screen_setup always requires exactly 3 argument bytes). Others have a minimum length. For example, draw_line requires at least enough bytes to encode the position, color, and one character, but the length byte can extend this for variable content. render_text accepts up to 99 argument bytes, allowing long text strings.

CommandLength typeArg count
screen_setupstrict3
draw_charstrict4
draw_linestrict6
render_textvariable3 + text length (max 99)
cursor_movestrict2
draw_at_cursorstrict2
clear_screenstrict0
renderstrict0
Bytes 3…N β€” Instruction Bytes

The remaining bytes carry the actual arguments, in the exact order defined by the command's signature. Each byte is interpreted as an ASCII character value and converted accordingly: 0x50 becomes the integer 80, 0x41 becomes the character A, and 0x07 becomes the color index for white in the current color mode. The expected type (int, string, or char) is determined by the command's signature for that argument position.

Final Byte β€” End of File (0xFF)

The entire input must be terminated with a single 0xFF byte. This signals to the parser that there are no further commands to read. A missing 0xFF will cause a validation error.

Command Chaining

Multiple commands can be chained together in a single input. After the terminal has consumed the argument bytes declared by a command's length byte, it expects the very next byte to be another command ID (or the 0xFF end-of-file marker). The argument length byte makes this unambiguous: the parser always knows exactly how many bytes belong to the current command before it looks ahead.

0x01
cmd: screen_setup
0x03
len: 3
0x50
width=80
0x18
height=24
0x01
16colors
0x02
cmd: draw_char
0x04
len: 4
0x00
x=0
0x00
y=0
0x07
white
0x41
char='A'
0xFF
EOF

Two chained commands: screen_setup then draw_char, terminated by 0xFF

Error handling is applied independently at each command boundary. If an argument count is wrong or an unknown command byte is encountered, the error is caught and reported precisely for that command, without corrupting the interpretation of surrounding commands in the chain.

Worked Example Streams

The streams below are real examples you can try. Each is broken down byte by byte so you can follow exactly how the parser reads them. Paste any of the raw streams into the terminal to see them in action.

Stream 1

Setup β†’ draw character β†’ draw line

0x01 0x03 0x50 0x18 0x01  0x02 0x04 0x00 0x00 0x07 0x41  0x03 0x06 0x3C 0x02 0x03 0x0A 0x07 0x2A  0xFF
BytesRoleInterpretation
0x01Command IDscreen_setup
0x03Arg length3 argument bytes follow
0x50Arg 1 β€” width0x50 = 80 β†’ screen width: 80
0x18Arg 2 β€” height0x18 = 24 β†’ screen height: 24
0x01Arg 3 β€” color mode0x01 β†’ 16colors
0x02Command IDdraw_char
0x04Arg length4 argument bytes follow
0x00Arg 1 β€” x0x00 = 0
0x00Arg 2 β€” y0x00 = 0
0x07Arg 3 β€” color0x07 β†’ white (16colors index)
0x41Arg 4 β€” char0x41 = ASCII 'A'
0x03Command IDdraw_line
0x06Arg length6 argument bytes follow
0x3CArg 1 β€” x0x3C = 60
0x02Arg 2 β€” y0x02 = 2
0x03Arg 3 β€” length0x03 = 3
0x0AArg 4 β€” extra0x0A = 10
0x07Arg 5 β€” color0x07 β†’ white
0x2AArg 6 β€” char0x2A = ASCII '*'
0xFFEnd of FileStream complete
Stream 2

Stream 1 + cursor move at the end

0x01 0x03 0x50 0x18 0x01  0x02 0x04 0x00 0x00 0x07 0x41  0x03 0x06 0x3C 0x02 0x03 0x0A 0x07 0x2A  0x05 0x02 0x14 0x05  0xFF

Identical to Stream 1, with one additional command appended before 0xFF:

BytesRoleInterpretation
0x05Command IDcursor_move
0x02Arg length2 argument bytes follow
0x14Arg 1 β€” x0x14 = 20
0x05Arg 2 β€” y0x05 = 5
0xFFEnd of FileStream complete

This demonstrates how chaining works: appending the next command's bytes, with the parser reading the cursor_move command ID immediately after consuming draw_line's 6 declared argument bytes.

Stream 3

Setup β†’ render text ("hello brother")

0x01 0x03 0x50 0x18 0x01  0x04 0x10 0x28 0x02 0x07 0x68 0x65 0x6C 0x6C 0x6F 0x20 0x62 0x72 0x6F 0x74 0x68 0x65 0x72  0xFF
BytesRoleInterpretation
0x01 0x03 0x50 0x18 0x01screen_setup80 Γ— 24, 16colors (same as above)
0x04Command IDrender_text
0x10Arg length16 argument bytes follow
0x28Arg 1 β€” x0x28 = 40
0x02Arg 2 β€” y0x02 = 2
0x07Arg 3 β€” color0x07 β†’ white
0x68 0x65 0x6C 0x6C 0x6FText bytes 1–5h e l l o
0x20Text byte 60x20 = ASCII space
0x62 0x72 0x6F 0x74 0x68 0x65 0x72Text bytes 7–13b r o t h e r
0xFFEnd of FileStream complete. Total: "hello brother" (13 bytes) + 3 positional args = 16 βœ“

Notice how the length byte 0x10 (=16) tells the parser exactly how many bytes of text to consume, even though text is variable-length. The arg count is the key: 3 fixed args (x, y, color) + 13 character bytes = 16.

Stream 4

Full composition: text, two lines, and "Merry Christmas!!"

0x01 0x03 0x50 0x18 0x01 0x04 0x10 0x28 0x02 0x07 0x68 0x65 0x6C 0x6C 0x6F 0x20 0x62 0x72 0x6F 0x74 0x68 0x65 0x72 0x03 0x06 0x3C 0x02 0x03 0x0A 0x07 0x2A 0x03 0x06 0x0A 0x02 0x0A 0x16 0x01 0x2A 0x04 0x14 0x1E 0x0C 0x06 0x4D 0x65 0x72 0x72 0x79 0x20 0x43 0x68 0x72 0x69 0x73 0x74 0x6D 0x61 0x73 0x21 0x21 0xFF
BytesCommandInterpretation
0x01 0x03 0x50 0x18 0x01screen_setup80 Γ— 24, 16colors
0x04 0x10 0x28 0x02 0x07 …0x72render_textx=40, y=2, white, "hello brother" (13 chars, total 16 args)
0x03 0x06 0x3C 0x02 0x03 0x0A 0x07 0x2Adraw_linex=60, y=2, length=3, extra=10, white, '*'
0x03 0x06 0x0A 0x02 0x0A 0x16 0x01 0x2Adraw_linex=10, y=2, length=10, extra=22, red (0x01), '*'
0x04 0x14 0x1E 0x0C 0x06 …0x21 0x21render_textx=30, y=12, cyan (0x06), "Merry Christmas!!" (17 chars, total 20 args)
0xFFEnd of File5 chained commands, stream complete

The "Merry Christmas!!" text breakdown

The final render_text has length byte 0x14 = 20. That's: 3 fixed args (x=0x1E=30, y=0x0C=12, color=0x06=cyan) + 17 text character bytes = 20 βœ“. The text 0x4D 0x65 0x72 0x72 0x79 0x20 0x43 0x68 0x72 0x69 0x73 0x74 0x6D 0x61 0x73 0x21 0x21 decodes as M-e-r-r-y-[space]-C-h-r-i-s-t-m-a-s-!-! = "Merry Christmas!!"

Common ASCII β†’ Hex Reference

Instruction bytes for characters and numbers are plain ASCII. Here are frequently used values:

Char / ValueHexDecimal
Space ( )0x2032
!0x2133
*0x2A42
00x3048
90x3957
A0x4165
Z0x5A90
a0x6197
z0x7A122
Width 800x5080
Height 240x1824
Height 300x1E30

F. Readable (String) Mode

Launched with python terminal.py --readable, this mode accepts natural command strings. Each string command is validated, converted to its hex equivalent internally, then executed through the same hex pipeline.

Example session:

screen_setup 80 24 16colors
draw_char 5 3 green @
render_text 10 5 cyan Hello World
render

Commands are entered one per line. Each command name must match exactly (case-sensitive) and be followed by the correct number of arguments in order.

G. Command Reference

All accepted commands are listed below. Commands apply to both hex mode and readable mode. The signature column shows the argument order for readable mode.

screen_setup0x013 args

Initialises the screen with the given dimensions and color mode. Must be called before any draw commands.

Signature

screen_setup <width: int> <height: int> <color_mode: string>

Example

screen_setup 80 24 16colors
draw_char0x024 args

Draws a single character at the specified (x, y) position in the given color.

Signature

draw_char <x: int> <y: int> <color: string> <char: char>

Example

draw_char 0 0 white A
draw_line0x035 args

Draws a horizontal line of the given length starting at (x, y), filled with the specified character and color.

Signature

draw_line <x: int> <y: int> <length: int> <color: string> <char: char>

Example

draw_line 60 2 10 white *
render_text0x04variable (up to 99) args

Renders a string of text starting at (x, y) in the given color. The text can span multiple words. All remaining tokens after the color argument are treated as the text.

Signature

render_text <x: int> <y: int> <color: string> <text: string...>

Example

render_text 40 2 white hello brother
cursor_move0x052 args

Moves the cursor to the specified (x, y) position without drawing anything.

Signature

cursor_move <x: int> <y: int>

Example

cursor_move 20 5
draw_at_cursor0x062 args

Draws a single character at the current cursor position in the given color. Use cursor_move first to position the cursor.

Signature

draw_at_cursor <color: string> <char: char>

Example

draw_at_cursor white A
clear_screen0x070 args

Clears the entire screen. Takes no arguments.

Signature

clear_screen

Example

clear_screen
render0x080 args

Flushes and renders everything drawn so far to the screen. Call this after your drawing commands to display output.

Signature

render

Example

render

H. Color Modes

The screen_setup command accepts one of three color mode strings. The mode you choose determines which color names are valid for subsequent draw commands.

monochrome

Two colors only: black and white.

blackwhite

16colors

Standard 16-color terminal palette.

blackredgreenyellowbluemagentacyanwhitebright_blackbright_redbright_greenbright_yellowbright_bluebright_magentabright_cyanbright_white

256colors

Extended 256-color mode. Refer to the repository for the complete color mapping.

I. How It Works (Pipelines)

Under the hood, both modes pass through rigorous validation and parsing before execution. Understanding the pipeline helps you debug unexpected errors.

Hex Pipeline

1
Hex Input Validation: Ensures every token in the raw input is parseable as a hex byte.
2
Command Parsing: Splits the stream into individual command chunks, each terminated by 0xFF.
3
Command Validation: Verifies each chunk has the correct number of argument bytes for its command.
4
Command Execution: Iterates through validated commands and executes each one.

String (Readable) Pipeline

1
Pipeline Instantiation: StringCommandController identifies the command and instantiates the matching CommandPipeline subclass.
2
Structure Validation: Checks that the correct number of arguments is provided.
3
Argument Validation: Ensures each argument matches its expected type (int, string, char) and is a recognised value (e.g. valid color name).
4
Hex Conversion: Converts all arguments to their hex byte representations.
5
Execution: Passes the assembled hex stream to the standard hex executor.

J. Full Examples

Example 1: Hello World (readable mode)

Set up an 80Γ—24 screen, write "Hello World" in cyan at position (10, 5), then render.

screen_setup 80 24 16colors
render_text 10 5 cyan Hello World
render

Example 2: Hello World (hex mode)

The exact equivalent as a hex stream:

0x01 0x03 0x50 0x18 0x01 0xFF 0x04 0x63 0x0A 0x05 0x06 0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64 0xFF 0x08 0x00 0xFF

Example 3: Drawing a border (readable mode)

Set up a screen and draw a line of asterisks along the top.

screen_setup 80 24 16colors
draw_line 0 0 80 white *
render

Example 4: Cursor positioning (readable mode)

Move the cursor then draw at the cursor's position.

screen_setup 80 24 16colors
cursor_move 40 12
draw_at_cursor yellow #
render

K. Troubleshooting & FAQ

Q: The terminal says my hex value is invalid.

A: Make sure every token starts with 0x and is followed by exactly two hex digits (e.g. 0x0A, not 0xA). Check that you haven't included extra spaces or stray characters.

Q: I get an 'incorrect argument count' error.

A: Double-check the command signature in the Command Reference section. Each command expects a specific number of arguments. For render_text, remember that all words after the color argument are treated as the text (no quotes needed).

Q: My color name isn't recognised.

A: Color names are case-sensitive and must match exactly (e.g. bright_blue not BrightBlue). Also confirm that the color you're using is available in the color mode you initialised with screen_setup.

Q: Nothing is showing up on screen.

A: Make sure you call render after your drawing commands. Without render, buffered draw operations are not displayed.

Q: Python says 'module not found' for argparse.

A: argparse is part of the Python standard library since Python 3.2. Ensure you're running Python 3.8 or higher with python --version.

L. Glossary

Hex stream
A sequence of hexadecimal byte values (e.g. 0x01 0x03 ...) representing commands and their arguments.
0xFF (END_OF_FILE)
A sentinel byte that marks the end of a command stream. Every command sequence must be terminated with 0xFF.
Command byte
The first byte of a command stream that identifies which command to run (e.g. 0x01 = screen_setup).
Readable mode
The --readable flag enables human-readable string commands instead of raw hex input.
Color mode
The palette mode used by the terminal: monochrome, 16colors, or 256colors. Set via screen_setup.
Cursor
A virtual pointer to a position on screen. Moved with cursor_move, used by draw_at_cursor.
Pipeline
The series of validation and transformation steps that a command passes through before execution.
CommandPipeline
A base class in the codebase extended by each command's specific pipeline implementation, following the Open/Closed Principle.