Skip to content

Corg-Labs/knot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

ASCII Torus Knot Spinner in C

A terminal-based 3D ASCII torus-knot animation written in C.

This program renders a rotating (p, q)-torus knot directly inside the terminal using mathematical projection, trigonometry, depth buffering, and ASCII shading techniques.

The animation continuously rotates in real-time and simulates 3D lighting entirely using text characters.

The default knot is a trefoil knot (p=2, q=3), the simplest non-trivial knot in mathematics.

This project focuses on learning:

  • terminal rendering
  • parametric 3D curves
  • tube geometry around a curve
  • Frenet-style orthonormal frames
  • 3D projection math
  • trigonometry in graphics
  • depth buffering
  • animation loops
  • low-level rendering concepts in C

Features

  • Real-time rotating ASCII torus knot
  • 3D perspective projection
  • Depth buffer (Z-buffer) implementation
  • ASCII lighting and shading
  • Pure terminal rendering
  • Written entirely in C
  • Configurable (p, q) winding numbers
  • Uses trigonometric functions for rotation

How It Works

The program mathematically walks along the center curve of a torus knot and wraps a thin tube around that curve. Every point on the tube is rotated, projected to the terminal, and shaded by its surface normal.

For every frame:

  • Clears previous frame buffer
  • Walks the knot curve at thousands of points along parameter t
  • For each t, builds an orthonormal frame perpendicular to the tangent
  • Sweeps a circle around the tube cross-section
  • Applies rotation transformations
  • Projects 3D points into 2D screen space
  • Computes brightness from the surface normal
  • Uses ASCII characters as pixels
  • Prints the updated frame to the terminal

The animation repeats continuously to create smooth rotation.


Tutorial / Rendering Pipeline

1. Create Screen Buffers

Two buffers are created:

char  buf[1920];
float zbuf[1920];
  • buf[] stores ASCII characters
  • zbuf[] stores depth values (Z-buffer)

This allows proper 3D overlap rendering.


2. Parametrize the Torus Knot

A (p, q)-torus knot is the curve:

x(t) = (R + a cos(qt)) cos(pt)
y(t) = (R + a cos(qt)) sin(pt)
z(t) =  a sin(qt)

For p=2, q=3 this traces a trefoil knot.


3. Build a Tube Around the Curve

For every value of t along the curve we compute:

  • the tangent vector T(t) (derivative of the curve)
  • two perpendicular unit vectors N, B forming the cross-section plane
  • a circle of radius tube around the curve in that plane

This sweeps a smooth tube along the knot.


4. Apply Rotation

Rotation variables:

A += 0.04;
B += 0.02;

control rotation over time.

Trigonometric functions:

sin()
cos()

are used to rotate 3D coordinates around the X and Y axes each frame.


5. Project 3D → 2D

Perspective projection converts 3D points into terminal coordinates:

int xp = WIDTH / 2 + K1 * ooz * x2;
int yp = HEIGHT / 2 - K1 * 0.5 * ooz * y2;

where ooz = 1 / (z + CAM_Z) creates the illusion of depth.


6. Depth Buffering (Z-buffer)

if (ooz > zbuf[o])

ensures closer points overwrite farther points.

This prevents rendering artifacts where the knot winds in front of itself.


7. ASCII Shading

Brightness values are mapped to characters:

".,-~:;=!*#$@"

Different characters simulate lighting intensity.

Example:

.  -> dark
@  -> brightest

The brightness comes from the dot product of the rotated surface normal with a fixed light direction.


8. Terminal Rendering

The frame is drawn using:

putchar()

and terminal cursor reset escape sequences:

printf("\x1b[H");

This redraws frames in-place to create animation.


Build

Compile using:

gcc knot.c -o knot -lm

Or just:

make

The -lm flag links the math library.


Run

./knot

Customizing the Knot

Edit these constants at the top of main() in knot.c:

const float p = 2.0f, q = 3.0f;  // try 3/2, 3/5, 5/2, 5/3 ...
const float R = 1.0f, a = 0.5f;
const float tube = 0.18f;
  • p=2, q=3 -> trefoil knot
  • p=3, q=2 -> also a trefoil
  • p=3, q=5 -> cinquefoil
  • p=5, q=2 -> Solomon's seal knot

gcd(p, q) must equal 1 for the curve to be a single knot rather than several linked circles.


Example Output

                                     !!!
                                  ;~::;~:;==
                                :::.....-;;;;
                                ~-..  =!!.:;;;!!
                                ~=!=;;:-~:-:::;=!!
                               :=;;::~,. .--,  ,!!:
                               ;;;,~;=!= ....  :!!:
                               ::, ,:-:!!!.., !!!:-
                               ~~-~   -;=======~:~
                               .-~::;=!!.~::::~.
                                 .,:::;=~.

(The actual knot rotates continuously in the terminal.)


Concepts Practiced

  • Parametric curves
  • Tube geometry along a curve
  • Orthonormal frames in 3D
  • 3D coordinate systems
  • Perspective projection
  • Rotation matrices
  • Trigonometry in graphics
  • ASCII rendering
  • Frame buffering
  • Z-buffering
  • Animation loops
  • Terminal graphics
  • Real-time rendering

Dependencies

Standard C libraries only:

  • stdio.h
  • math.h
  • string.h
  • unistd.h

No graphics engine required.


Inspiration

Inspired by the classic ASCII donut demo created by Andy Sloane.

A torus knot is a sibling of the torus — instead of wrapping once around the donut, the curve wraps p times one way and q times the other before closing on itself.

About

► A terminal-based 3D ASCII torus-knot animation written in C.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors