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

Introduction

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.

Conclusion

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.

Code

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];
      }
    }
  }

  stdout.write('\x1b[H');
  for (let k = 0; k < 1760; k++) {
    stdout.write(output[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);
}

main();

Apple releases firmware update for all Airpods

Apple has released a new firmware update, version 5E133, for AirPods, AirPods Pro, and AirPods Max. This update is available for the AirPods second and third generations, the first and second generations of AirPods Pro, and the AirPods Max. This update is an improvement from the previous version, 5B59, that was released in January.

The firmware update was briefly released by Apple but was pulled soon after. It has been made available again to all eligible devices. Users need not take any action as firmware updates are delivered automatically while AirPods are charging and in Bluetooth range of an iPhone, iPad, or Mac that’s connected to Wi-Fi. Unfortunately, there is no way to install the firmware update manually.

Apple has not provided any detailed release notes for the firmware update, but it is generally expected that this update will fix bugs and enhance the overall performance of the AirPods. There have been no indications of any feature changes to the AirPods.

To check if your AirPods have the latest firmware version, make sure that you have the latest version of iOS or iPadOS. Then, go to Settings > Bluetooth, and tap the Info button next to the name of your AirPods. Scroll down to the About section to find the firmware version. For macOS users, press and hold the Option key while choosing Apple menu ? > System Information. Click Bluetooth, then look under your AirPods for the firmware version. With macOS Ventura, you can also choose Apple menu ? > System Settings, click Bluetooth, then click the Info button next to the name of your AirPods.

If you do not have an Apple device nearby, you can set up an appointment at an Apple Store or with an Apple Authorized Service Provider to update your firmware.