Transcendence

Digital Artwork
JavaScript
p5.js

Start clicking, holding and moving your mouse to interact with the artwork

Process

Conceptual Focus

Where does digital art exist within the art world? An extension of the physical, a space of its own, or something in between?

In our increasingly technological world, digital art is more prevalent than ever. While some artists are concerned that it may replace man-made art, others embrace it. Should the rejection of physical mediums and acceptance of technology’s presence into the artworld be looked down upon?

The aesthetic direction of my sketch was significantly informed by the work of Yves Klein, whose artistic philosophy served as a major conceptual foundation. This colour was used in Klein’s works to evoke a sense of transcendence and otherworldly presence because of its rich, intense pigment. While Klein’s influence remains central, my interpretation reimagines his ideas within a contemporary digital context, creating a deliberate contrast between his analogue era and the technology-driven world of the 21st century. By appropriating Klein’s monochromatic colour scheme through a digital medium, the pigment is changed by technological limitations, questioning whether digital art has a place in the art world. In this work, I ask viewers to reflect upon the evergrowing presence of technology in the art and furthermore, in our own lives.

Person with curly hair and white shirt touching digital art piece with black splatters on a blue background.

Justifications

In creating this sketch, I used a bold, monochromatic colour palette inspired by Klein’s work to reflect the same sense of transcendence. The chaotic movement of the 'particles' suggests cells or atoms, referencing scientific discoveries that were once thought of as mystical or supernatural. As the user moves their mouse, these particles begin to attract each other, forming a large circular shape. This visual is similar to a black hole and is meant to encourage reflection on large-scale concepts like astronomy and astrology. These ideas often go beyond human understanding and relate to the metaphysical themes explored by both Klein and myself.
I also used a large amount of negative space to represent the emptiness of the void beyond physical life and consciousness. At the conclusion of the sketch, I included a quote from Yves Klein: "Blue has no dimensions. It is beyond dimensions." (Klein, n.d.), to reinforce the central themes and visual direction of the work.

The Code

// Array to store particle objects
let particles = [];
// Boolean value to track if the image (new background) is shown
let imageShown = false;
// Boolean value track if the text is shown
let textShown = false;
// Variable for rotation of the circle pattern
let patternRotation = 0;
// Variables for the radius of the circle pattern
let patternRadius;
let invertedRadius;

function setup() {
  // Create a canvas the size of the window
  createCanvas(windowWidth, windowHeight);
  // Defines a new "fake" canvas the size of the window
  newCan = createGraphics(windowWidth, windowHeight);
  // Sets the colour of the fake canvas to black
  newCan.background(0, 0, 0);
  // Sets colour mode to HSB (hue, saturation, brightness)
  colorMode(HSB);
  // Sets the frame rate to 60 frames per second
  frameRate(60);
}

function draw() {
  // Calls functions for background and circle colours
  backCol();
  circCol();

  // Determines acceleration of jitter based on mouse x-axis position - the more central the mouse's x coordinate is, the faster the jitter
  let acc;
  if (mouseX < width / 3) {
    acc = map(mouseX, 0, width / 2, 1, 8);
  } else {
    acc = map(mouseX, width / 2, width, 8, 1);
  }

  // for loop displays and updates the position of each particle in the array
  for (let i = 0; i < particles.length; i++) {
    particles[i].show();
    particles[i].move(acc);
  }

  // prints the frame count for reference
  print(frameCount);

  // Checks if the first particle in the array's radius is larger than the canvas width
  if (particles[0] && particles[0].r > width) {
    // if this is true, imageShown is set to true and draws image (new "fake" canvas with black background is visible)
    imageShown = true;
    image(newCan, 0, 0);
  }

  // Check if image is shown and enough frames have passed
  if (imageShown && frameCount > 1600) {
    // If true, display text
    displayText();
    textShown = true;
  }

  // Check if text is shown and enough frames have passed
  if (textShown && frameCount > 1800) {
    // If true, display pattern
    displayPattern();
  }
}

// Function to set background colour
function backCol() {
  let backBright;
  // map brightness to mouse position on x axis - brightness increases depending on how central mouse's x position is, revealing blue colour
  if (mouseX < width / 2) {
    backBright = map(mouseX, 0, width / 2, 0, 100);
  } else {
    backBright = map(mouseX, width / 2, width, 100, 0);
  }
  background(240, 100, backBright);
}

// Function to set circle colour
function circCol() {
  let circBright;
  // map brightness to mouse position on x axis - brightness decreases depending on how central mouse's x position is, circles appear darker towards the middle
  if (mouseX < width / 2) {
    circBright = map(mouseX, width / 2, 0, 0, 100);
  } else {
    circBright = map(mouseX, width, width / 2, 100, 0);
  }
  fill(240, 100, circBright);
}

// Function to add particles when mosue is clicked
function mouseClicked() {
  let genParticle = new Particle(random(width), random(height));
  particles.push(genParticle);
}

// Function for when mouse is dragged
function mouseDragged() {
  // New random particles generated when framecount is greater than 1000
  if (frameCount > 1000) {
    let extraParticles = 2;

    for (let i = 0; i < extraParticles; i++) {
      let genParticle = new Particle(random(width), random(height));
      particles.push(genParticle); /*code attained from '7.3 Arrays of Objects - p5.js Tutorial'
      by The Coding Train accessed via https://youtu.be/fBqaA7zRO58?si=RZ3wDvgsEVJPi7Gh&t=733
      // used to push/ generate a new particle at the end of the particle array, 
      I have implemented it so that multiple particles can be generated to create a chaotic mood. */
    }
  }
  // Once 10 particles have been generated through mouse clicked function, particles move towards mouse position and jitter in size
  if (particles.length > 10) {
    for (let i = 0; i < particles.length; i++) {
      particles[i].attract(mouseX, mouseY);
      particles[i].sizeInc(random(-3, 3));

      // after 1000 frames, particles expand when mouse is dragged

      if (frameCount > 1000) {
        particles[i].sizeInc(1);
      }
    }
  }
}

// Particle class
class Particle {
  constructor(xPosition, yPosition) {
    this.xPos = xPosition;
    this.yPos = yPosition;
    this.r = 10; // radius of particles
  }

  // Function to update particle position (jitter)
  move(speed) {
    this.xPos += random(-speed, speed);
    this.yPos += random(-speed, speed);
  }

  // Function to make particles reappear once off screen
  wrap() {
    if (this.xPos > width) {
      this.xPos = 0;
    }
    if (this.xPos < 0) {
      this.xPos = width;
    }
    if (this.yPos > height) {
      this.yPos = 0;
    }
    if (this.yPos < 0) {
      this.yPos = height;
    }
  }

  // Function to display particle
  show() {
    noStroke();
    circle(this.xPos, this.yPos, this.r);
    this.wrap();
  }

  // function to attract particle to a target position
  attract(targetX, targetY) {
    this.xPos = lerp(this.xPos, targetX, 0.05);
    this.yPos = lerp(this.yPos, targetY, 0.05);
  }

  // Function to change particle size
  sizeInc(growthSpeed) {
    // this.r += random(-growthSpeed, growthSpeed);
    this.r += growthSpeed;
  }
}

// Function to display text
function displayText() {
  fill(255);
  textAlign(CENTER);
  textSize(20);
  text(
    "blue has no dimensions. it is beyond dimensions.",
    width / 2,
    height / 2
  );
}

// Function to display rotating pattern
function displayPattern() {
  let numPatternCircs = 50;
  let patternCircCol = color(240, 100, 100);

  // map mouse position to radius of circles in pattern
  let patternRadius = map(mouseX, 0, width, 150, width);
  let invertedRadius = map(mouseX, 0, width, width, 150);

  /// move the circles to the middle of the canvas
  translate(width / 2, height / 2);
  rotate(patternRotation);

  // Creates a whole circle of 50 ellipses
  let angleInc = TWO_PI / 50;

  // Draw a pattern of increasing radius
  for (let i = 0; i < numPatternCircs; i++) {
    let currentAngle = i * angleInc;
    let patternX = cos(currentAngle) * patternRadius;
    let patternY = sin(currentAngle) * patternRadius;

    fill(color(240, 100, 100));
    noStroke();
    ellipse(patternX, patternY, 10, 10);
  }

  // Draw a pattern of decreasing radius
  for (let i = 0; i < numPatternCircs; i++) {
    let currentAngle = i * angleInc;
    let invertedX = cos(currentAngle) * invertedRadius;
    let invertedY = sin(currentAngle) * invertedRadius;

    fill("white");
    noStroke;
    ellipse(invertedX, invertedY, 10, 10);
  }
  patternRotation += 0.01;
}

// Allows canvas to be resized depending of size of window
function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}