ASCII SANTA HAT

3D Terminal Rendering Magic

Donut.c on steroids — A full 3D engine in your terminal

                  @@@@@
                @@@@@@@@
              @@@@@@@@@@
            @@@@@@@@@@@@@
          @@@@@@@@@@@@@@@@
        @@@@@@@@@@@@@@@@@@@
      @@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@
=============================================
*** MERRY CHRISTMAS *** HO HO HO ***
=============================================
Explore the Math View on GitHub
Scroll to learn more

How It Works

🎨 Parametric Geometry

Three distinct 3D surfaces: a curved cone (hat body), torus (fluffy rim), and sphere (pom-pom), all mathematically defined.

🔄 Rotation Matrices

Two-axis rotation using X and Y rotation matrices for smooth 3D spinning animation.

📐 1/z Projection

Perspective projection using inverse depth—the same trick from the classic donut.c renderer.

🎯 Z-Buffer

Depth buffer ensures closer points override farther ones for proper 3D occlusion.

💡 Dot Product Lighting

Normal vectors dotted with light direction determine ASCII character brightness.

🌈 ANSI Colors

Red hat body, white pom-pom and rim, yellow scrolling text—all in glorious terminal colors.

The Mathematics

1. Rotation Around X-Axis (Tilt)

y₂ = y·cos(A) - z·sin(A) z₂ = y·sin(A) + z·cos(A)

2. Rotation Around Y-Axis (Spin)

x₃ = x·cos(B) - z₂·sin(B) y₃ = y₂ z₃ = x·sin(B) + z₂·cos(B)

3. Perspective Projection

ooz = 1 / z₃ xₛcᵣₑₑₙ = W/2 + Sₓ·(ooz·x₃) yₛcᵣₑₑₙ = H/2 + 2 - Sᵧ·(ooz·y₃)

Where Sₓ = 55 and Sᵧ = 30 control the scale

Hat Body Geometry (Curved Cone)

rad(t) = 1.8·(1 - t) spineₓ(t) = 1.8·t² spineᵧ(t) = -1.5 + 3.5·t - t³ x = spineₓ(t) + rad(t)·cos(θ) y = spineᵧ(t) z = rad(t)·sin(θ)

Rim (Torus)

x = (R + r·cos(φ))·cos(θ) y = h + r·sin(φ) z = (R + r·cos(φ))·sin(θ) R = 1.7, r = 0.4, h = -1.5

Lighting (Dot Product)

L = N · Light_direction L = nₓ·0.5 + nᵧ·0.5 - nᵤ·0.5 ASCII_chars = ".,-~:;=!*#$@" char_index = clamp(int(L * 8), 0, 11)

Higher luminance values map to brighter characters

Implementation

def plot_pixel(x, y, z, color, luminance): # Rotate around X-axis y2 = y * cosA - z * sinA z2 = y * sinA + z * cosA # Rotate around Y-axis x3 = x * cosB - z2 * sinB y3 = y2 z3 = x * sinB + z2 * cosB z3 += 6.0 # Move in front of camera # Perspective projection ooz = 1 / z3 xp = int(WIDTH / 2 + 55 * ooz * x3) yp = int((HEIGHT / 2 + 2) - 30 * ooz * y3) # Z-buffer test idx = xp + yp * WIDTH if ooz > zbuffer[idx]: zbuffer[idx] = ooz # Map luminance to ASCII char = chars[int(luminance * 8)] output[idx] = color + char + RESET

80×30 characters × ~100 points per shape × 3 shapes = Beautiful 3D ASCII art

Inspired By

This project is a love letter to a1k0n's donut.c

Taking the same mathematical principles and pushing them further:

✓ Multiple complex geometries
✓ ANSI color support
✓ Scrolling text billboard
✓ More sophisticated shading

"Sometimes the best way to understand something
is to rebuild it from scratch and make it your own."