Dot Shapes Lab

In which you will apply vertex attributes, shader programs, and a VAO in order to fill your framebuffers with the dotted outlines of two shapes that can be described algorithmically.

Circle

Your first challenge is to plot a circle. Actually, circles don't exist in digital tools. The best you can do is plot a regular polygon with many sides. Complete the following steps to create a circle regular polygon renderer.

Copy the hello-orange project folder to a sibling folder named lab01-circle.
Remove node_modules from lab01-circle and rebuild it by running npm install. Something about the directory structure makes this step necessary, but your instructor isn't exactly sure what.
Start up a web server and verify that you see the original two dots.
While the code is still working, you are going to factor out the VBO and VAO creation to a separate function so that you can regenerate them without reinitializing everything. Create a new function and name it generateCircle.
Move the code in initialize that deals with positions, attributes, and vao to generateCircle. Leave the shader code in place.
Just after the shader program is assigned in initialize, call generateCircle. You should see the two dots as before.
Make generateCircle accept parameters named n and radius.
Modify the positions array so that it contains n evenly spaced vertices on the perimeter of a circle of the given radius. A vertex's location can be computed by turning its angle and radius into Cartesian coordinates: $$ \begin{aligned} x &= \text{radius} \cdot \cos \theta \\ y &= \text{radius} \cdot \sin \theta \\ z &= 0 \end{aligned} $$
Call generateCircle with various parameters. Ensure that you can see circles of various sizes and sample rates.
Add the following HTML just inside the opening body tag in index.html to give the user an interface for changing the sample rate and radius:
<div class="controls">
  <label>n</label>
  <input id="n-input" type="text">
  <label>radius</label>
  <input id="radius-input" type="text">
</div>
Add the following CSS at the bottom of style.css to position the controls atop the canvas:
.controls {
  position: absolute;
  top: 5px;
  right: 5px;
  display: grid;
  grid-template-columns: auto auto;
  grid-gap: 2px 5px;
  justify-items: end;
  z-index: 1;
}
Add the following JavaScript to main.js to handle changes to the HTML inputs. After you confirm that entering input calls synchronize, replace the TODO comment in synchronize with real calls to your functions.
let nInput;
let radiusInput;

async function initialize() {
  // other getElementById calls...
  nInput = document.getElementById('n-input');
  radiusInput = document.getElementById('radius-input');

  // VAO, VBO, shader program setup...

  // other event listeners...
  nInput.addEventListener('input', synchronize);
  radiusInput.addEventListener('input', synchronize);
}

function synchronize() {
  // Release any previous VAO and VBOs.
  vao?.destroy();
  attributes?.destroy();

  const n = parseInt(nInput.value);
  const radius = parseFloat(radiusInput.value);
  console.log(n, radius);
  // TODO: regenerate circle and redraw.
}
Show your functioning application to your instructor to receive credit.

Lissajous Curve

Your second challenge is to render Lissajous curves. Do an image search on the web to see what they are. Just like the circle, they have parametric definitions:

$$ \begin{aligned} x(t) &= a \cdot \sin(t) \\ y(t) &= b \cdot \sin(\text{ratio} \cdot t + \text{shift}) \\ z(t) &= 0 \end{aligned} $$

The domain of \(t\) is \([0, 2\pi]\). Complete the following steps to build a Lissajous renderer.

Copy the lab01-circle project folder to a sibling folder named lab01-lissajous, and rebuild node_modules as before.
Rename generateCircle to generateLissajous.
Modify the controls so there are five inputs with labels and IDs n, a, b, ratio, and shift.
Grab references to these five elements using getElementById.
Call synchronize whenever these inputs are modified.
Parse the values of these inputs in synchronize. Only parameter n is an integer. The others are reals.
Modify generateLissajous and its calls to generate Lissajous curves instead of a circle. The code will have a very similar structure to your circle generator.
Show your functioning application to your instructor to receive credit.