p5.js icon indicating copy to clipboard operation
p5.js copied to clipboard

preloading with loadFont does not work in instance mode

Open kontur opened this issue 4 years ago • 13 comments

Hi there!

Most appropriate sub-area of p5.js?

  • [x] Build tools and processes
  • [x] Core/Environment/Rendering
  • [x] DOM

Details about the bug:

  • p5.js version: 1.3.1
  • Web browser and version: Any
  • Operating System: MacOS 11.3
  • Steps to reproduce this:

Loading a font in instance mode the "preload" is not consistently called and executed before the setup. Only reloading the browser (without hard refresh) the fonts load.

WIth: Separate html with container, loading library and sketch.js included at foot of html:

This DOES NOT work. The sketch will run before the font has loaded.

var s = function(p) {
	var font = null;
	p.preload = function () {
		console.log("preload")
		font = p.loadFont('assets/fonts/test.ttf')
	}
	p.setup = function() {
		console.log("setup", font)
	}
}
new p5(s);

This will print to console:

  • setup null
  • preload

This DOES work, but uses "global" mode. The sketch will preload the font, then run.

new p5();
var font = null;
function preload() {
	console.log("preload")
	font = loadFont('assets/fonts/test.ttf')
}
function setup() {
	console.log("setup", font)
}

This will print to console:

  • setup null (not sure why this gets called once?)
  • preload
  • setup Object { parent: {…}, cache: {}, font: {…} }

Is there something one needs to take into account when trying to get preload to work with instance mode?

kontur avatar May 11 '21 06:05 kontur

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already.

welcome[bot] avatar May 11 '21 06:05 welcome[bot]

I was not able to recreate this either in the editor, or after downloading the sketch and running it from the local filesystem (see my test here). Can you list the exact steps to recreate?

dhowe avatar May 11 '21 08:05 dhowe

I can't reproduce either - also note that manually calling new p5(); will instantiate p5.js twice so I don't think it's a good idea (and that's why you get the setup message twice)

micuat avatar May 11 '21 15:05 micuat

I think calling the p5() was in the tutorial to make "global mode" happen "after the fact". This is really a weird issue. I've tried @dhowe 's code and that works standalone, and imo I've reduced my code those bits, but there still no consistent pointer what's going wrong. I'm investigating some more and report back.

kontur avatar May 11 '21 15:05 kontur

Okay, I've managed to reduce it to a reproducible case for Mac OS 11.3 Firefox 88.0.1 — and this is ... ethereal.

With this in sketch.js and that font file existing (and the png existing):

var s = function(p) {
  
  var font;
  p.preload = function() {
    console.log('preload', typeof font);
    font = p.loadFont('Resagokr.otf');
    console.log('preload.done', typeof font);
  };
  
  p.setup = function() {
    console.log('setup', typeof font);
    p.createCanvas(400, 400);
  };

  p.draw = function() {
    console.log('draw', typeof font);
    p.background(255);
    p.textFont(font, 100);
    p.text('hello', 100,200);
    p.noLoop();
  };
};

new p5(s);

This will work:

<!doctype html>
<html lang="en">
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>
</head>
<body>
    <script src="sketch.js"></script>
</body>
</html>

And this will fail with a Uncaught Error: null font passed to textFont when hard refreshing (cmd + shift + r):

<!doctype html>
<html lang="en">
<head>
    <style type="text/css">
    body {
        background: url("some.png");
    }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>
</head>
<body>
    <script src="sketch.js"></script>
</body>
</html>

The CSS does not need to be inline; including a CSS with a url resource seems to be enough to throw off the preload requirement detection — p5 just goes ahead and runs the setup, only to run (I think) the preload sequence "late" after the url resource/CSS has fully loaded.

If I change the content of sketch.js from the "instance" mode to "global" notation like so:

var font;
function preload () {
	console.log('preload', typeof font);
	font = loadFont('AbrilFatface-Regular.otf');
	console.log('preload.done', typeof font);
};

function setup () {
	console.log('setup', typeof font);
		createCanvas(400, 400);
};

function draw () {
	console.log('draw', typeof font);
	background(255);
	textFont(font, 100);
	text('foo', 100, 200);
	noLoop();
};

… the url in the CSS don't seem to matter and I get no more errors.

So in effect, using "instance mode" with any CSS that loads resources will break the preload (of fonts, at least).

kontur avatar May 11 '21 17:05 kontur

@dhowe @micuat can either of you reproduce this?

kontur avatar May 13 '21 11:05 kontur

Please review the tags after trying to reproduce.

kontur avatar May 17 '21 12:05 kontur

@kontur could you set up the example which causes the error on p5.js web editor so others can test it easily?

micuat avatar May 17 '21 13:05 micuat

I was having similar issues while trying to load in images and I found that calling new p5() with window.onload got preload to work.

var p5sk;
window.onload = () => {
  p5sk = new p5(s);
};

ScottGrogin avatar Dec 26 '21 20:12 ScottGrogin

Hi, I have the same issue.

I tried the code by @dhowe (https://editor.p5js.org/rednoyz/sketches/EjxQSJyVj) and I get this error:

index.html:1 Access to XMLHttpRequest at 'file:///home/cocconat/Documents/web/debris/vodkalaterra/sunny.otf' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, brave, chrome-untrusted, https.

I verified that the font is actually in the directory by clicking on the link and downloading it.

This is the full log:

preload undefined
main.js:89 preload.done object
index.html:1 Access to XMLHttpRequest at 'file:///home/cocconat/Documents/web/debris/vodkalaterra/sunny.otf' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, brave, chrome-untrusted, https.
p5.min.js:3 Font could not be loaded sunny.otf
(anonymous) @ p5.min.js:3
(anonymous) @ p5.min.js:3
Dr.r.onerror @ p5.min.js:3
error (async)
Dr @ p5.min.js:3
M.load @ p5.min.js:3
f.default.loadFont @ p5.min.js:3
(anonymous) @ p5.min.js:3
p.preload @ main.js:88
_start @ p5.min.js:3
load (async)
_ @ p5.min.js:3
(anonymous) @ main.js:106
p5.min.js:3 GET file:///home/cocconat/Documents/web/debris/vodkalaterra/sunny.otf net::ERR_FAILED

aquaresima avatar Jan 29 '22 14:01 aquaresima

@aquaresima Loading external files including fonts will require running a server. Loading files will not work locally over the file:// protocol usually seen when running the html file directly instead of through a server. You can read more here.

limzykenneth avatar Jan 29 '22 17:01 limzykenneth

Thanks, I was reading indeed! Let's say that I can put this on the web-server that I use to share my content online. When I refer to point to that link

I get this other error:

'Access-Control-Allow-Origin' header

WTH?

aquaresima avatar Jan 29 '22 17:01 aquaresima

If your sketch and the web server hosting the resource is not on the same domain, the server hosting the resource will need to include the 'Access-Control-Allow-Origin' header with the right value in order for any other site to use the resource. It is generally called CORS headers. More here.

If you are trying to develop a sketch locally, you should prefer using local servers as per the link I shared in the previous comment. If you are trying to share the sketch online on your own website, you will need to either host everything from the same domain or be able to modify how your server serves the resources (by adding the 'Access-Control-Allow-Origin' header).

limzykenneth avatar Jan 29 '22 18:01 limzykenneth