Translating Donut.c to JavaScript: A Step-by-Step Guide


The famous “Spinning Donut” is a mesmerizing animation created using a relatively short piece of C code, known as “donut.c”. In this article, we will go through the process of translating the original “donut.c” code to JavaScript, and make it work in a command-line environment using Node.js. We will also discuss the steps taken to fix the issues encountered during the translation process.

Donut.c translation to JavaScript

Step 1: Understanding the Original C Code

To translate “donut.c” to JavaScript, we must first understand the underlying logic of the original C code. The key concepts in the code are:

  1. Trigonometric functions (sine and cosine) are used to create a 3D effect.
  2. Two nested loops iterate over the points on the surface of the torus (the doughnut shape).
  3. A z-buffer is employed to determine which points are visible from the viewer’s perspective.
  4. Characters from a predefined character set are used to represent different levels of brightness.

Step 2: Creating a Basic JavaScript Structure

We will begin by creating a basic JavaScript file named “donut.js”. We will use Node.js to run this script in the command line. The main structure of the JavaScript code should include:

  1. Importing the required Node.js modules.
  2. Defining a renderFrame function to draw the spinning doughnut for each frame.
  3. Defining a main function to handle the animation loop.
  4. Calling the main function to start the animation.

Step 3: Translating the C Code to JavaScript

Next, we will carefully translate each part of the C code to its corresponding JavaScript code. The most important parts include:

  1. Converting the trigonometric functions to their JavaScript equivalents (e.g., Math.sin and Math.cos).
  2. Adjusting the nested loops and increment values to create a smooth animation.
  3. Using JavaScript arrays for the z-buffer and output buffer.
  4. Replacing C’s putchar function with the stdout.write function provided by Node.js.

Step 4: Fixing Aspect Ratio and Positioning Issues

During the translation process, we may encounter issues related to the aspect ratio and positioning of the doughnut. To fix these issues, we can:

  1. Adjust the coefficients for the x and y calculations in the renderFrame function to match the aspect ratio of the characters in the terminal.
  2. Modify the loop increments and x and y calculations to center the doughnut on the screen.
  3. Test the animation at each step to ensure it renders correctly.

Step 5: Optimizing the JavaScript Code

After fixing the aspect ratio and positioning issues, we might need to optimize the JavaScript code for better performance. We can achieve this by:

  1. Adjusting the loop increments to find a balance between animation quality and performance.
  2. Replacing single-letter variable names with more descriptive names for better readability.


In this article, we have walked through the process of translating the original “donut.c” code to JavaScript, running it in a command-line environment using Node.js. By understanding the logic behind the C code, creating a basic JavaScript structure, translating the code, fixing issues, and optimizing performance, we have successfully created a spinning doughnut animation in JavaScript.


Save code as donut.js
Run with:
node donut.js

const { stdout } = require('process');

function renderFrame(angleA, angleB) {
  const output = Array(1760).fill(' ');
  const zBuffer = Array(1760).fill(0);

  const sinAngleA = Math.sin(angleA);
  const cosAngleA = Math.cos(angleA);
  const sinAngleB = Math.sin(angleB);
  const cosAngleB = Math.cos(angleB);

  for (let loopA = 0; loopA < 2 * Math.PI; loopA += 0.1) {
    const cosLoopA = Math.cos(loopA);
    const sinLoopA = Math.sin(loopA);
    for (let loopB = 0; loopB < 2 * Math.PI; loopB += 0.05) {
      const sinLoopB = Math.sin(loopB);
      const cosLoopB = Math.cos(loopB);
      const h = cosLoopA + 2;
      const distance = 1 / (sinLoopB * h * sinAngleA + sinLoopA * cosAngleA + 5);
      const t = sinLoopB * h * cosAngleA - sinLoopA * sinAngleA;

      const x = Math.floor(40 + 20 * distance * (cosLoopB * h * cosAngleB - t * sinAngleB));
      const y = Math.floor(12 + 10 * distance * (cosLoopB * h * sinAngleB + t * cosAngleB));
      const outputIndex = x + 80 * y;
      const brightnessIndex = Math.floor(8 * ((sinLoopA * sinAngleA - sinLoopB * cosLoopA * cosAngleA) * cosAngleB - sinLoopB * cosLoopA * sinAngleA - sinLoopA * cosAngleA - cosLoopB * cosLoopA * sinAngleB));

      if (1760 > outputIndex && outputIndex > 0 && distance > zBuffer[outputIndex]) {
        zBuffer[outputIndex] = distance;
        output[outputIndex] = '.,-~:;=!*#$@'[brightnessIndex > 0 ? brightnessIndex : 0];

  for (let k = 0; k < 1760; k++) {
    if (k % 80 === 79) stdout.write('\n');

function main() {
  let angleA = 0;
  let angleB = 0;

  setInterval(() => {
    angleA += 0.04;
    angleB += 0.08;
    renderFrame(angleA, angleB);
  }, 16);


Donald Trump writing quick sort function in JavaScript

Quick sort is the best sorting algorithm ever. Nobody knows sorting better than me. I invented Quick sort. It’s very simple. You just pick a pivot element, which is always the greatest element in the array, because I always pick the greatest things. Then you divide the array into two parts: one part with all the losers who are less than the pivot, and one part with all the winners who are greater than or equal to the pivot. Then you sort those parts recursively, which means you do the same thing over and over again until you get tired of winning.

Quick sort is very fast and efficient. It’s faster than any other sorting algorithm. It’s faster than merge sort, which is a disaster. It’s faster than heap sort, which is a joke. It’s faster than insertion sort, which is for losers. Quick sort is so fast, it can sort an array in O(n log n) time on average, which is a very big number that only I understand. Trust me, I have a very good brain.

Quick sort works in place, which means it doesn’t need any extra space or memory. It’s very smart and economical. Unlike merge sort, which wastes a lot of space and money on copying arrays. Quick sort is also very stable, which means it preserves the order of equal elements. Unlike some other sorting algorithms that mess up the order and create chaos.

Quick sort is the greatest sorting algorithm of all time. Nobody can beat Quick sort. Nobody can stop Quick sort. Quick sort will make America great again!

// This is the best quick sort function ever. Nobody can do it better than me.
function makeArrayGreatAgain(array) {
  // If the array is empty or has one element, it's already great. Very smart.
  if (array.length <= 1) {
    return array;
  // Pick a random genius element from the array. 
  // I have great intuition for this.
  let geniusIndex = Math.floor(Math.random() * array.length);
  let genius = array[geniusIndex];
  // Create two subarrays for elements less than and greater than the genius. 
  // Very efficient.
  let losers = [];
  let winners = [];
  // Loop through the array and compare each element to the genius. Very fast.
  for (let i = 0; i < array.length; i++) {
    // Skip the genius element itself. Very clever.
    if (i === geniusIndex) {
    // If the element is less than or equal to the genius, 
    // push it to the losers subarray. Very fair.
    if (array[i] <= genius) {
    // If the element is greater than the genius, 
    // push it to the winners subarray. Very strong.
    else {
  // Recursively sort the losers and winners subarrays and 
  // concatenate them with the genius. Very elegant.
  return [...makeArrayGreatAgain(losers), genius, ...makeArrayGreatAgain(winners)];

Color Labs, Inc. takes rights to your photos if you use their Color app!

Color Labs, Inc. Color appBe careful what you upload with new Color app from Color Labs, Inc. You will be surprised that by using their Color app you give them all rights to your photos! From their ‘Terms of Service’.

Continue reading

How to read HFS+ disks in Windows

How to read HFS+ disks in WindowsYou can use utility from your Snow Leopard install disc

Continue reading

Apple iPhone 2.1 Software Update

Apple iPhone 2.1 Software UpdateApple released the iPhone 2.1 software update that contains many bug fixes and improvements. To get it, connect your iPhone to your computer using iTunes 8 and click Check for Update.


Continue reading