Most appropriate sub-area of p5.js?
p5.js version
2.3.4
Web browser and version
Chrome 152.0.7977.64
Operating system
Linux (Ubuntu 24.04.4 LTS)
Steps to reproduce this
There are two separate problems with the load*Shader() functions.
1. loadNormalShader() fails in every build with TypeError: this.withGlobalStrands is not a function.
In src/webgl/material.js line 1861 it calls this.withGlobalStrands(...), but withGlobalStrands is a module-level function (line 19), not a method. The other four loaders call it directly.
2. In p5.min.js, all five loaders fail (loadFilterShader, loadMaterialShader, loadNormalShader, loadColorShader, loadStrokeShader) with TypeError: this._internal is not a function.
_internal() is only defined in the FES module (src/friendly_errors/param_validator.js), which the minified build leaves out. Other files guard the call (this._internal ? this._internal(cb) : cb(), e.g. src/io/files.js), but material.js calls it unguarded at lines 528, 532, 1640, 1860, 2025 and 2288. This looks like a regression: loadFilterShader() works in the 2.2.0 minified build.
In both cases the error is caught inside the loader (logged to the console and/or passed to the failure callback) and the function resolves to undefined.
Steps:
- Put the files below in a folder and serve it locally (e.g.
python3 -m http.server 8000)
- Open
http://localhost:8000 with p5.min.js in the script tag: both loaders log undefined with this._internal is not a function
- Change the script tag to
p5.js and reload: loadFilterShader returns a Shader, but loadNormalShader still logs undefined with this.withGlobalStrands is not a function
Snippet:
<!-- index.html -->
<!doctype html>
<html>
<head><meta charset="utf-8"></head>
<body>
<script src="p5.min.js"></script> <!-- swap to p5.js for step 3 -->
<script src="sketch.js"></script>
</body>
</html>
// sketch.js
async function setup() {
createCanvas(100, 100, WEBGL);
const f = await loadFilterShader('filter.frag');
console.log('loadFilterShader:', f);
const n = await loadNormalShader('normal.js');
console.log('loadNormalShader:', n);
}
// filter.frag
precision highp float;
varying vec2 vTexCoord;
uniform sampler2D tex0;
void main() {
gl_FragColor = vec4(1.0 - texture2D(tex0, vTexCoord).rgb, 1.0);
}
// normal.js (any valid JavaScript works; the error happens before the hooks run)
getWorldInputs((inputs) => inputs);
Console output
With p5.min.js:
TypeError: this._internal is not a function
at n.loadFilterShader (p5.min.js:27:42)
at async setup (sketch.js:4:13)
loadFilterShader: undefined
TypeError: this._internal is not a function
at n.loadNormalShader (p5.min.js:65:1211)
at async setup (sketch.js:7:13)
loadNormalShader: undefined
With p5.js:
loadFilterShader: Shader {_renderer: RendererGL, ...}
TypeError: this.withGlobalStrands is not a function
at p5.js:58182:44
at fn._internal (p5.js:74783:12)
at fn.loadNormalShader (p5.js:58182:23)
at async setup (sketch.js:7:13)
loadNormalShader: undefined
Possible fix
- Remove
this. on line 1861 of material.js.
- Make
_internal safe when FES isn't loaded, either with a pass-through fallback in core (similar to the FES stubs added to main.js in a67a76a) or by guarding the six calls like the rest of the codebase. I'm happy to go with whichever maintainers prefer.
- Add visual tests for
loadNormalShader, loadColorShader and loadStrokeShader, which currently have none. Only loadMaterialShader and loadFilterShader are covered in test/unit/visual/cases/webgl.js.
This was discussed in the 🌸contribute-to-p5 Discord channel and I would like to work on it. I used an AI assistant to help investigate this bug.
Most appropriate sub-area of p5.js?
p5.js version
2.3.4
Web browser and version
Chrome 152.0.7977.64
Operating system
Linux (Ubuntu 24.04.4 LTS)
Steps to reproduce this
There are two separate problems with the
load*Shader()functions.1.
loadNormalShader()fails in every build withTypeError: this.withGlobalStrands is not a function.In
src/webgl/material.jsline 1861 it callsthis.withGlobalStrands(...), butwithGlobalStrandsis a module-level function (line 19), not a method. The other four loaders call it directly.2. In
p5.min.js, all five loaders fail (loadFilterShader,loadMaterialShader,loadNormalShader,loadColorShader,loadStrokeShader) withTypeError: this._internal is not a function._internal()is only defined in the FES module (src/friendly_errors/param_validator.js), which the minified build leaves out. Other files guard the call (this._internal ? this._internal(cb) : cb(), e.g.src/io/files.js), butmaterial.jscalls it unguarded at lines 528, 532, 1640, 1860, 2025 and 2288. This looks like a regression:loadFilterShader()works in the 2.2.0 minified build.In both cases the error is caught inside the loader (logged to the console and/or passed to the failure callback) and the function resolves to undefined.
Steps:
python3 -m http.server 8000)http://localhost:8000withp5.min.jsin the script tag: both loaders logundefinedwiththis._internal is not a functionp5.jsand reload:loadFilterShaderreturns aShader, butloadNormalShaderstill logsundefinedwiththis.withGlobalStrands is not a functionSnippet:
Console output
With
p5.min.js:With
p5.js:Possible fix
this.on line 1861 ofmaterial.js._internalsafe when FES isn't loaded, either with a pass-through fallback in core (similar to the FES stubs added tomain.jsin a67a76a) or by guarding the six calls like the rest of the codebase. I'm happy to go with whichever maintainers prefer.loadNormalShader,loadColorShaderandloadStrokeShader, which currently have none. OnlyloadMaterialShaderandloadFilterShaderare covered intest/unit/visual/cases/webgl.js.This was discussed in the 🌸contribute-to-p5 Discord channel and I would like to work on it. I used an AI assistant to help investigate this bug.