I'm coding this starry background for a website using p5.js
, and it has 3 elements:
There is a background that slowly intervals between black and white. This is done by drawing many white circles with varying levels of brightness over a black background
There are many small white stars that decrease in alpha values, and once the alpha hits zero, the star randomly moves to another part of the screen and the alpha resets
Stars within a short distance of the cursor will connect a line from the star's position to the cursor's position
Visualization (the intersection between the lines is where the cursor is; the letter "N" and the word "night" are HTML elements):
However, this can cause a bit of lag on some devices/browsers, so I'm looking to speed it up. Are there optimizations I could do to improve the performance?
let time = 0;
let stars = [];
class Star {
constructor() {
this.x = random(0, width);
this.y = random(0, height);
this.brightness = random(0, 255);
this.inc = random(3, 5);
if (random() < 0.5)
this.inc *= -1;
}
display() {
fill(255, 255, 255, this.brightness);
noStroke();
circle(this.x, this.y, 1.5);
this.brightness += this.inc;
if (this.brightness >= 255) {
this.inc *= -1;
}
else if (this.brightness <= 0) {
this.inc *= -1;
this.x = random(0, width);
this.y = random(0, height);
}
}
}
function setup() {
createCanvas(windowWidth - 17, 500);
for (let a = 0; a < 50; ++a)
stars.push(new Star());
}
function draw() {
// background
clear();
fill(0);
rect(0, 0, width, height);
// circles (white gradient)
noStroke();
let clr = (Math.sin(time) * 50) + 10;
for (let d = (clr + 150); d >= 0; d -= 1) {
fill(128 - (d / (clr + 150)) * 128);
circle(0, 0, d * (height / 50));
}
time += 0.005;
// stars and cursor lines
for (let a = 0; a < stars.length; ++a) {
stars[a].display();
// `a % 2 == 0` is just to add some randomness to which stars get chosen to form a line
if (a % 2 == 0 && dist(stars[a].x, stars[a].y, mouseX, mouseY) < 200) {
stroke(255);
strokeWeight(2);
line(stars[a].x, stars[a].y, mouseX, mouseY);
}
}
}
1 Answer 1
Reduce state changes
There are two ways that you can improve performance and they depend on what render engine you use (WebGL or Canvas2D). However this is code review and I can not tell you how, only how to improve your code.
The inner loop that renders stars and the lines needs to separate the render states to reduce the number of state changes.
State changes are the main source of slowdown Things like changing color, images, draw type all involve a state change.
Thus you can render the stars and lines using 2 loops. Both identical you your one loop. However each loop not needing to constantly change render state.
Example
// draw stars
for (const star of stars) { star.display(); }
var i = 0;
var distSqrt = 200 * 200;
// setup line state
stroke(255);
strokeWeight(2);
// Find and draw lines
for (const star of stars) {
if (i % 2 === 0) {
const x = star.x - mouseX;
const y = star.y - mouseY;
if (x * x + y * y < distSqrt) {
line(star.x, star.y, mouseX, mouseY);
}
}
i++;
}
Result??
How much of an improvement this will be will depend on many factors. Give it a try. If you are not happy with the result please ask the question at stack overflow rather than code review. Good luck.