Sun & Moon Created in P5.js (with tutorial)

Posted on by Kevin Foong

This sketch was created using P5.js, the Javascript version of Processing. Click anywhere. The "moon" will gravitate towards the closest "sun" and orbit.

See Sun & Moon

Code Explanation

Here is a simple walkthrough of this sketch. P5.js has two predefined functions, setup and draw. setup is called once and once only when the program starts. It is where you initialise all your variables. draw is called repeatedly in an endless loop and it is where you put all the code for your animation.

Here we are using an array to store our Sun objects and another array to store our Moon objects. Clicking the mouse on the screen will create a new Moon object at the x,y location of the mouse.

let suns = [];
let num_suns = 6;
let moons = [];

function setup() {
  for (let i = 0; i < num_suns; i++) {
    suns.push(new Sun(random(0,width), random(0,height)));

function draw() {
  for (let i = 0; i < suns.length; i++) {
  for(let i=0; i<moons.length; i++) {

function mouseClicked() {
  moons.push(new Moon(mouseX,mouseY));

The Sun class is fairly simple. The size of the sun is randomly generated, and display just draws an ellipse (circle) in a random x,y position on the screen.

class Sun {
  constructor(x, y) {
    //size of sun
  display() {
  getx () {
    return this.x;
  gety() {
    return this.y;
  getrad() {
    return this.rad;

The Moon class is where we do all the mathematics. We calculate all our variables in the constructor.

Firstly we use pythagoras theorem to calculate the distance between the moon objects and each sun to identify which is the closest sun. Pythagoras theorem states that 'c' ('c' in our case is the distance between moon and sun) is the square root of 'a' to the power of 2 plus 'b' to the power of 2. We can easily calculate 'a' and 'b' via the x,y position of the sun and moon.

With the closest sun identified we next calculate theta (Θ) using trigonometry. Theta is the angle between our sun and moon. We will use theta later to animate the moon orbitting.

Finally the display function is used to render the moon. We use P5.js lerp function to help us animate the moon gravitating towards the sun. Once the moon reaches the sun we then use trigonometry to render the moon orbiting the sun. Here we make use of the theta value we calculated earlier.

The formula for animating an object in a circle is:

x = sin(Θ) * speed
y = cos(Θ) * speed

class Moon {
  constructor(x,y) {
    this.loccount=0; //for the lerp
    // calculate distance to each sun
    this.adj = [];
    this.opp = [];
    this.dist = [];
    for (let i=0; i<num_suns; i++) {
      this.adj[i]  = this.x-suns[i].getx();
      this.opp[i] = suns[i].gety()-this.y;
      this.dist[i] = sqrt(pow(this.adj[i],2)+pow(this.opp[i],2));
    // for the closest sun, get the index and the distance
    this.closestsun_index = 0;
    this.closestsun_dist = 99999999;
    for (let i=0; i<num_suns; i++) {
      if (this.dist[i] < this.closestsun_dist) {
        this.closestsun_index = i;
        this.closestsun_dist = this.dist[i];
    // get theta
    this.theta = atan2(this.opp[this.closestsun_index],this.adj[this.closestsun_index])+PI/2;
    // get the sun object
    this.sun = suns[this.closestsun_index];
    // get sun radius
    this.radmotion = this.sun.getrad() + 8;
    // calculate distance to sun
    this.distspin = this.closestsun_dist - this.radmotion;
    // calculate spin speed
    this.spinspeed = random(-0.04,0.04);
  display() {
    if (!this.startspin) {
      this.locx = lerp(this.x, this.sun.getx(), this.loccount/this.closestsun_dist); 
      this.locy = lerp(this.y, this.sun.gety(), this.loccount/this.closestsun_dist); 
    } else {
      this.locx = this.sun.getx() + sin(this.theta)*this.radmotion;
      this.locy = this.sun.gety() + cos(this.theta)*this.radmotion;
      this.theta += this.spinspeed;

See full source code on Github


Tags: processing, p5.js


Stevcymn on

Amoxicillin S Side Effects <a href=>cialis 5 mg best price usa</a> Cialis 20mg Uk Propecia Problemas Si

Email is optional