Skip to main content

Activating Moon Mode

Use the --moon flag to display a circular ASCII art moon instead of the animated joke:
bofa --moon
This renders a static ASCII moon with craters and displays it immediately without animations.

How It Works

Moon mode generates ASCII art using mathematical circle rendering with the payload text centered inside.

Circle Algorithm

The moon is drawn using a distance-based circle algorithm from moon.py:25-31:
for y in range(-R, R + 1):
    row = list(" " * (W * 2 + 1))
    for x in range(-W, W + 1):
        dist = math.sqrt((x / CHAR_ASPECT) ** 2 + y ** 2)
        cx = x + W
        if abs(dist - R) < 0.5:
            row[cx] = "#"
How it calculates the circle:
  1. For each character position (x, y), calculate the distance from the center
  2. Adjust for character aspect ratio (characters are taller than wide)
  3. If distance is within 0.5 units of the radius R, draw a # symbol
  4. This creates a circular outline

Character Aspect Ratio

Terminal characters are not square - they’re approximately twice as tall as they are wide. The algorithm compensates for this:
CHAR_ASPECT = 2.0
When calculating distance, x-coordinates are divided by CHAR_ASPECT to make the circle appear round instead of elliptical:
dist = math.sqrt((x / CHAR_ASPECT) ** 2 + y ** 2)

Moon Sizing

The moon automatically sizes itself to fit your terminal:
cols, rows = shutil.get_terminal_size(fallback=(80, 24))
R = min(rows // 2 - 1, 10)  # Radius, max 10 lines
W = int(R * CHAR_ASPECT)     # Width accounting for aspect ratio

if W * 2 + 1 > cols:
    W = (cols - 1) // 2
    R = int(W / CHAR_ASPECT)
Sizing logic:
  • Radius is half the terminal height minus 1, capped at 10
  • Width is calculated from radius × aspect ratio
  • If the moon is too wide, it resizes based on terminal columns
  • The final moon diameter is constrained to fit within your terminal

Crater Generation

Craters are randomly scattered inside the moon circle using a seeded random generator:
CRATERS = ("()", "o", ".", "o", ".", "()")
rng = random.Random(42)  # Seeded for consistent output

Crater Placement Algorithm

From moon.py:41-53:
inner_positions = [
    x + W
    for x in range(-W, W + 1)
    if math.sqrt((x / CHAR_ASPECT) ** 2 + y ** 2) < R - 0.5
    and row[x + W] == " "
]
if inner_positions:
    for _ in range(max(1, len(inner_positions) // 12)):
        c = rng.choice(CRATERS)
        pos = rng.choice(inner_positions)
        for j, ch in enumerate(c):
            if pos + j < len(row) and row[pos + j] == " ":
                row[pos + j] = ch
How craters are placed:
  1. Find all positions inside the circle (distance < R - 0.5) that are empty spaces
  2. For approximately 1/12th of those positions, place a crater
  3. Randomly select a crater type from CRATERS
  4. Place it at a random empty position
  5. Multi-character craters like () span multiple positions

Crater Types

Six crater patterns are available:
  • () - Large crater (2 characters)
  • o - Medium crater
  • . - Small crater (appears twice for higher frequency)
The list includes duplicates to weight the probability: smaller craters appear more often than larger ones.

Center Payload

The text “Bofa deez nuts” is always centered in the middle row of the moon:
if y == 0:
    # place payload centered
    payload = BOFA.decode("utf-8")  # "Bofa deez nuts"
    start = W - len(payload) // 2
    for j, ch in enumerate(payload):
        row[start + j] = ch
This happens at y == 0, which is the vertical center of the moon. The text is positioned so it’s horizontally centered within the moon’s width.

Deterministic Output

The moon always looks the same for a given terminal size because the random number generator is seeded with 42:
rng = random.Random(42)
This ensures consistent, reproducible ASCII art across multiple runs.

Example Output Structure

          ###########
       ####  o  .  ####
     ###  .   ()   .  ###
    ##  o  . Bofa deez nuts ##
     ###  o    .  o  ###
       ####  .  o  ####
          ###########
Components:
  • # characters form the outer circle edge
  • ., o, () are randomly placed craters
  • Center row contains the payload text
  • Trailing spaces are trimmed from each line

Moon vs Regular Mode

The --moon argument is checked early in the main function:
if args.moon:
    from bofa.moon import play_moon
    play_moon()
    return
Moon mode:
  • No animations or effects
  • Instant output
  • Static ASCII art
  • Always uses the same payload text
  • No Unicode detection (works in all terminals)
Regular mode:
  • Multiple animated effects
  • Random effect selection
  • Unicode support detection
  • Terminal compatibility checks
  • Keyboard interrupt handling

Build docs developers (and LLMs) love