Loading screen with preload

Hi all, I’m using the function preload in my p5 project, because of that I have a couple of seconds of a white page at the beginning, so I want to create a loading screen.
I tried to do the following here:

and instead of the this could be some sweet graphics loading lots of bits I put a p5 sketch like that:

<div id="p5_loading" class="loadingclass"><script src="loading.js"></script></div>

now I this problem:
My code in loading.js is like that:

size = 0;
function setup(){
    createCanvas(window.innerWidth, window.innerHeight);
    background(38);
}

function draw(){
    background(38);
    fill(187);
    circle(width/2,height/2,sin(size)*50);
    size+=0.05;
}

the project gets stuck with this page (all you can see is the circle gets big and small in the background) and it doesn’t move to the main project after the reload.

what to do? Is possible at all to do something like that?
and if animations are possible, can I load image to the loading screen? that’s mean I need to use preload to there as well? (smells like recursion :sweat_smile:)

thanks :hugs:

Hi @Omri,

Well you are spicing stuff a bit! :wink:

So you want to display a loading screen that is basically a p5 sketch itself.

Basically since loadImage can be asynchronous and accepts a callback, you can call it in setup() and in draw() display your loader if not loaded:

let bigImage;
let loaded = false;

function setup() {
  createCanvas(400, 400);
  
  bigImage = loadImage(
    "https://images.pexels.com/photos/358457/pexels-photo-358457.jpeg",
    () => loaded = true
  );
}

function draw() {
  if (!loaded) {
    background(0);
    // Your spinner here
  } else {
    background(220);
  }
}
1 Like

I believe they’ve meant styling the element w/ CSS stuff, not another p5js sketch.

Besides only 1 global mode sketch can be active within a single web frame.

For extra global mode sketches you’ll have to place them inside separate <iframe>:
https://developer.Mozilla.org/en-US/docs/Web/HTML/Element/iframe

I believe you can include an <img> element as the <div> content:

1 Like

@josephh thanks again for the help :slight_smile:
your solution is working for me for the sound file (with loadSound).
but I have in my sketch also shaders and video.
for the video I’m using createVideo, so this is counting as loading something? does it have a callback to use your option with?
for the shade as I can see here:

it does have a callback, but something weird is happening when I try your method: the set is started running in a loop. do you have any idea why is that? I’m doing the same as I did with the loadSound

@GoToLoop
So if I can use only CSS that’s means I cannot do animation at the loading screen?

p5js got a default loading <div> element which we can replace w/ our own.

I dunno the full extent of what an HTML element can do, but I believe they can be styled w/ some CSS animation:

1 Like

Yes it has a callback:

createVideo(src, [callback])

Here is a code that loads an image and a video asynchronously using promises and Promise.all to wait for multiple asynchronous tasks to finish:

let bigImage;
let video;

let loaded = false;
let loadingError = false;
let timeValue = 0;

function promiseLoadImage(url) {
  return new Promise((resolve, reject) =>
    loadImage(url, resolve, reject)
  )
}

function promiseCreateVideo(url) {
  return new Promise((resolve, reject) => {
    const video = createVideo(url, () => resolve(video));
  })
}

function easeOutCubic(x) {
  return 1 - Math.pow(1 - x, 3);
}

function setup() {
  createCanvas(400, 400);

  Promise.all([
    promiseLoadImage(
      "https://images.pexels.com/photos/358457/pexels-photo-358457.jpeg"
    ),
    promiseCreateVideo("https://upload.wikimedia.org/wikipedia/commons/transcoded/6/60/Wikipedia_logo_puzzle_globe_spins_horizontally_and_vertically%2C_revealing_the_contents_of_all_of_its_puzzle_pieces_%284K_resolution%29_%28VP9%29.webm/Wikipedia_logo_puzzle_globe_spins_horizontally_and_vertically%2C_revealing_the_contents_of_all_of_its_puzzle_pieces_%284K_resolution%29_%28VP9%29.webm.120p.vp9.webm")
  ]).then((results) => {
    [img, vid] = results;

    bigImage = img;
    video = vid;
    video.play();
    video.loop();

    loaded = true
  }).catch(e => loadingError = true)
}

function loader() {
  push();
  translate(width / 2, height / 2);
  noFill();
  strokeWeight(10);
  stroke(50, 200, 0);
  const endOffset = (period) => easeOutCubic((sin(timeValue + period) + 1) / 2)
  arc(0, 0, 100, 100, timeValue + endOffset(0) * HALF_PI, timeValue + PI + endOffset(HALF_PI) * HALF_PI);
  pop();
}

function draw() {
  background(200);

  if (loadingError) {
    stroke(255, 0, 0);
    strokeWeight(5);
    line(width - 50, 50, 50, height - 50);
    line(50, 50, width - 50, height - 50);
    noLoop();
    return;
  }

  if (!loaded) {
    loader();
  } else {
    image(bigImage, 0, 0);
  }

  timeValue += 0.1;
}
2 Likes

@josephh you’re the best!
do you have any idea about the loadShader problem?

1 Like

Again this in the reference:

Syntax:

loadShader(vertFilename, fragFilename, [callback], [errorCallback])

Have fun! :wink:

@josephh
that’s what I tried, but look at something strange, If I run this code:

let theShader;
function preload() {
  theShader = loadShader('shader.vert', 'shader.frag');
}

function setup() {
  pixelDensity(1);
  createCanvas(windowWidth, windowHeight, WEBGL);
  noStroke();
  console.log("DONE SET UP")
}

function draw() {
  theShader.setUniform('u_resolution', [width, height]);
  shader(theShader);
  rect(0, 0, width, height);
}

everything looks good:

But, when I try to use the callback:

let theShader;
let loaded = false;

function setup() {
  pixelDensity(1);
  createCanvas(windowWidth, windowHeight, WEBGL);
  theShader = loadShader('shader.vert', 'shader.frag',
    () => loaded = true
  );
  noStroke();
  console.log("DONE SET UP")
}

function draw() {
  if (!loaded) {
    background(200);
    fill(20)
    circle(width/2, height/2, 200);
  } else {
    theShader.setUniform('u_resolution', [width, height]);
    shader(theShader);
    rect(0, 0, width, height);
  }
}

I get that:


It looks like it running the setup() function a lot of times

have you ever seen something like that? am I using the callback wrong?
I used now the simplest shader so I don’t think the problem is with the shader.vert or the shader.frag

Yes it’s strange, maybe it’a a bug…

You should either load it in the setup() or preload() but not in both because it makes no sense.

Oh, that was a mistake when I copied it here, I didn’t use preload() the second time. :rofl:

Do you know what can I do about that bug?

This works fine for me:

let theShader;
let loaded = false;

function setup() {
  pixelDensity(1);
  createCanvas(windowWidth, windowHeight, WEBGL);
  theShader = loadShader('shader.vert', 'shader.frag',
    () => {
      loaded = true
      console.log("SHADER LOADED")
    }
  );
  noStroke();
  console.log("DONE SET UP")
}

function draw() {
  if (!loaded) {
    background(200);
    fill(20)
    circle(width / 2, height / 2, 200);
  } else {
    theShader.setUniform('u_resolution', [width, height]);
    shader(theShader);
    rect(0, 0, width, height);
  }
}

with those shaders: p5.js shaders

Thanks, I just tried your code and it is the same:

here is the code in the p5 web editor:

in your computer it’s working fine?

Ok this is really strange, thanks for sharing the editor link. Did you try locally on your own computer rather than on the online editor?

yep, the same problem.
Do you maybe know where is the code of loadShader() at the p5js code?
maybe I’ll look up if I can notice what causing the bug there

You forgot to link the GitHub issue there :wink:

1 Like

haha ya, I wanted to know if it’s really a bug on p5 or it’s just me :smiling_face_with_tear:
looks like it’s a bug :frowning:
if you have any idea how to fix it pls let me know.
thanks for all the help!