Support for Top-Level Global Mode
Increasing access
Parity with an existing feature in Processing. Also improves ease of use in ESM sketches especially.
Most appropriate sub-area of p5.js?
- [ ] Accessibility
- [ ] Color
- [x] Core/Environment/Rendering
- [ ] Data
- [ ] DOM
- [ ] Events
- [ ] Image
- [ ] IO
- [ ] Math
- [ ] Typography
- [ ] Utilities
- [ ] WebGL
- [ ] Build process
- [ ] Unit testing
- [ ] Internationalization
- [ ] Friendly errors
- [ ] Other (specify if possible)
Feature request details
Ideally p5 could support top-level global mode. createCanvas would be available globally and could be used to start p5 in top level global mode and create a canvas.
createCanvas(200, 200);
rect(20, 20, 50, 50);
There's a precedent for this in Processing. The Processing editor supports running sketches like this without a setup or draw method.
size(200, 200);
rect(20, 20, 50, 50);
There's also a broader precedent in the many programming languages that used to require some kind of main method, that now can run top-level code.
EDIT:
This would be especially useful in the context of p5 in an ESM (issue #7670) with top-level await, so there'd be no need for an async setup function.
await createCanvas(400, 400);
let logo = await loadImage('logo.avif');
p5.draw = function () {
background(logo);
};
It's also just nice in general to be able to declare and define variables on the file level.
await createCanvas(400, 400);
let r = random(100);
p5.draw = function () {
background(r);
};
Added this to a draft issue related to global mode documentation: https://github.com/orgs/processing/projects/21/views/8?pane=issue&itemId=107924677 - draft because I am not yet sure what the scope of that issue should be. However, I recognize that this is not primarily a clarification/documentation issue; I think what would be most helpful is for other users (especially educators or people who recently learned p5.js) to weigh in. From other conversations, it seems to be that documenting of what's currently possible is higher priority than considering adding top-level global behavior, but this is also open for discussion.
I strongly support adding top-level global mode to p5.js!
It would greatly improve usability for beginners, align p5.js more closely with Processing, and simplify writing ESM-compatible sketches.
Being able to call createCanvas() and draw shapes without needing a setup() function or manually managing instance variables would make learning and prototyping much easier, especially for educators and newcomers.
Thank you @LalitNarayanYadav for the support!
@ksen0 It's been a while since you requested comments on this and it seems that no one is against it. Could you give the green light on this and I'll explore how it could be implemented in p5 v2?
Also just to clarify, this isn't related to better documenting existing features, this is a request for new feature that doesn't currently exist in p5 v2 in any form.
@ksen0 @davepagurek Let me know what the next steps should be so we can get the ball rolling on this.
@ksen0 @davepagurek I'm ready to implement this.
Hi @quinton-ashley , although there have been no arguments against it, there has also not been an in-depth discussion. Like any additive feature, it would expand maintenance scope, so it cannot be added without in-depth consideration. Like any feature proposal, more detail would be needed for expected behavior. Although since the spring (when this was created) we have received various input from the community on p5.js 2.0, as well as shared the status board / open for discussion issues, there have been other higher-priority topics for making p5.js 2.0 better support learners and educators. Because there has not been more concrete community deliberation on this feature, the issue still does not have the level of detail needed for a feature (rather than documentation, as you said) request.
By more detail I mean, for example, consider:
let p = new p5();
createCanvas(200, 200);
p.draw = () => {
background(255, 0, 0);
rect(mouseX, mouseY, 100, 100);
};
background(0, 255, 0);
rect(20, 20, 50, 50);
With top-level global mode, the above is something that a learner might quite plausibly write, based on my teaching experience. I don't think that the expected order of execution here would easier for a beginner to understand, compared to the setup and draw pattern. Additionally, providing more options to beginners can also create more confusion, especially if the options may be different from what learners will encounter later in JavaScript more generally, or different from most of the existing example materials. This is just an example to illustrate was I see as unresolved about how this issue impacts inclusion/access (in this case, specifically the particular case of beginner friendliness). I hope this clarifies the status of the issue - in my opinion, it can stay open for comment in case there are additional perspectives that help move it along, but I don't think it is ready for work.
@ksen0 I could write a p5 v1 sketch with draw first, then setup, then preload, then variable declaration at the end, and say it wouldn't make sense to beginners.
function draw() {
background('red');
rect(mouseX, mouseY, 100, 100);
}
function setup() {
createCanvas(200, 200);
}
function preload() {
logo = loadImage('/q5js_logo.avif');
}
let logo;
So doing something the wrong (less human readable) way is bad? Beginners can make mistakes? Of course that's true. Sorry but I don't understand the point you're trying to make.
based on my teaching experience.
With respect, you're not a teacher (correct me if I'm wrong). What experience are you referring to?
I have eight years of tutoring and teaching experience with middle school and high school students. Your counter-example is not practical. What is your hypothetical student trying to do? Could you give a more real-world scenario?
Anyways, it'd be an easy mistake to correct. p5 could even throw a friendly error if a student tried to do stuff on the top-level after declaring draw.
To clarify, as you requested, Top-Level Global mode would remove two key barriers for entry:
- beginners could write simple sketches without needing to declare any functions (no setup, no draw)
- beginners could declare and define variables, that store resulting values from p5 functions, on a single line (ex.
loadImage)
Function syntax is something day one beginners are often told to overlook.
Needing to declare variables on a separate line is also something students consistently struggle with, even after using p5.js for a whole year. It's not a good user experience.
These observations are based on my experience with real students, not hypothetical examples.
Currently, large p5.js projects start with a lot of lines that declare variables, followed by a setup function with a lot of lines defining those variables. Requiring a setup function forces users to do a lot of extra typing or copy/pasting in this regard.
I don't think further debate on the value this feature could provide is necessary, since it has broad precedents in other programming languages and Processing itself. Does this request not align with the goals of the pr0s grants to increase interop between Processing and p5? You didn't address that point.
This issue has already been open for discussion for 8 months and no one else responded. Please don't delay this feature's implementation further and let's focus on the technical aspects of implementing it.
@GregStanton Care to add your opinion on this to facilitate a more in-depth discussion?
Just jumping in to try to separate out the proposals here. It sounds like there are a few things that we'd like to get out of this:
- Making global-like code easier to write in ESM sketches
- Supporting setup-free code like in Processing
Making global-like code easier to write in ESM sketches
For some technical context, the reason why ESM is sort of weird with global mode is that code in a <script type="module"> can access global things, but functions defined in there aren't global, so we don't detect function setup() {} and function draw() {}. The current workaround, which is a fairly small departure from regular global mode, is to write your code like this:
window.setup = function() {
createCanvas(200, 200)
}
window.draw = function() {
background('red')
}
IMO this is not a bad workaround right now and doesn't require any code changes to p5 yet, and is worth documenting. (Regardless of what we do, I think we could use a tutorial category on the site for p5 in different contexts, like ESM scripts, and React or Angular components -- p5 library changes are not required of those cases, but there are specific usage patterns that make it work, and just making them visible would go a long way.)
We can definitely also strive to make this easier to do, and this proposal is one way. Another potential option could be to let users write p5.setup = function() { ... } instead of window. This would require a change to the p5 codebase, but a fairly small one.
Supporting setup-free code like in Processing
I think there are some subtle technical challenges we'd have to figure out in order to make that work. Addons can now run asynchronous code in a presetup lifecycle hook, which they might use to e.g. load some resources that a function they expose then uses. When there is no setup function, it's unclear when those will run. I think we'll need to figure out that interaction before going ahead with a change there. Potentially this proposal could still be helpful even without the removed setup, or at least starting with that. It just means evaluating the ideas with respect to the other goals mentioned.
also, @quinton-ashley alluded to the fact that instance mode is pretty verbose with the nested callbacks. that also could be addressed, and there's this existing issue https://github.com/processing/p5.js/issues/7332 that we can talk about for that too, although maybe we can talk more about that over there and make this one be more global mode focused.
@davepagurek Yes fair point, I edited my previous comment to keep discussion here more focused, though there's overlap with #7332 which is a documentation issue as you said.
Also good point about the presetup hook being async in p5.js v2, that's something my examples wouldn't account for. I'll have to think more about that.
@davepagurek When a user is using p5 v2 without addons that impose an async presetup hook, it'd certainly be nice to be able to write little sketches like this.
createCanvas(200, 200);
rect(20, 20, 50, 50);
Could top-level createCanvas be synchronous and could it load all of p5's stuff into the global scope so that rect is available and the canvas could be drawn to?
When we do want to wait for p5 to fully load (including addons' async presetup hooks) then new p5() wouldn't cut it, and we can't await a constructor.
Related to this discussion, WebGPU can't be loaded synchronously because requestAdapter is async.
Dave already shared some info with me on how this would be achieved. Async createCanvas and createGraphics functions would also load WebGPU behind the scenes.
async function setup() {
await createCanvas(200, 200, WEBGPU);
}
So awaiting createCanvas could also be a way to wait for p5 to fully load (await any presetup hooks) in ESM top-level global mode.
await createCanvas(200, 200);
let logo = await loadImage('logo.avif');
p5.draw = function () {
background(logo);
};
Making all createCanvas calls awaitable could be a good way to get around the need for setup! It's a bigger API change so I don't think we're able to transition to that just yet, but it's something we're going to have to address regardless when WebGPU mode matures, so maybe that'll be the point at which we want to consider it more closely and make API changes like returning a promise instead of a renderer directly.
also: just made an issue here https://github.com/processing/p5.js-website/issues/999 to start making a place to describe these different usages of p5 on the website!
@davepagurek Ah yes, cause createCanvas returns the renderer element in p5 v2 currently.
I'd really appreciate if we could figure this out ASAP, because I'm already trying to plan curriculum that will use p5 v2 when it becomes the default in the web editor later this year.
@davepagurek I am mainly interested in top-level global mode in the context of p5's upcoming WebGPU mode. Do you have an idea of when the initial version will be released? Will it be before September 2026?
Added this to a draft issue related to global mode documentation: p5.js 2.x 🌱🌳 (view) - draft because I am not yet sure what the scope of that issue should be. However, I recognize that this is not primarily a clarification/documentation issue; I think what would be most helpful is for other users (especially educators or people who recently learned p5.js) to weigh in. From other conversations, it seems to be that documenting of what's currently possible is higher priority than considering adding top-level global behavior, but this is also open for discussion.
@ksen0 My experience is mostly teaching in university-level design and art programs. Generally, I don't teach module syntax and instance mode in beginner classes in that context. When I teach beginners with the p5.js editor, the most common hang-up I see related to this issue is that students try to use random() or color() in the global scope but can't because the functions haven't been injected into the global scope yet. Something like:
let r = random(0, 100);
function setup () {
}
function draw () {
}
This generates a friendly error message in the console and students either have trouble understanding the message or don't read it because it is rather long. It would be awesome if this just worked as expected, assigning a random number between 0-100 to variable r.
I could see how some educators might find it useful to be able to teach drawing and variables without having the setup() and draw() functions as Processing allows, though this isn't nearly as important to me as the issue described above! In a 10-week intro class, I usually introduce simple interactivity with mouseX & mouseY during the second week of class which necessitates having draw() and setup() in the code. I usually handwave on what a function is for the first 3-4 weeks of class, emphasizing that setup() runs once before the sketch appears while draw() repeats ~60 frames per second and that this is what the students need to know to get started. Having these two functions in the editor template code for a new project is really helpful and reminds students of the general program flow.
Again, my experience is mostly with university students so I'm not sure if this would be similar in K-12. Hope this info is useful!
students try to use random() or color() in the global scope but can't because the functions haven't been injected into the global scope yet.
@kjhollen Yes definitely similar in K-12, I've seen students try to do that too!
@ksen0 The confusion students experience when trying to use random() or color() before setup shows that p5’s initialization sequence isn’t that intuitive for beginners. This feature wouldn't just be something "nice to have" but could be a game changer for p5 v2 that solves this common issue.
It'd be awesome if this just worked as expected
Assuming that we could teach students to always use createCanvas (for 2D and WebGL non-ESM sketches) to load p5 before anything else, then we'd kinda get that "it just works" behavior on the top level for free, since users want to create a canvas at the beginning of nearly all sketches anyway.
But you seem to be suggesting a different idea, having p5 automatically put functions, that don't require a canvas, in the global scope. I like it but that could be tricky or impossible to implement in a way that's compatible with more advanced use cases, in which p5 is loaded alongside lots of other libraries, because automatically putting p5 functions on the global scope could cause functions with the same name to be overridden.
I had thought of other ways to check if p5 should use top-level global mode. Since JS functions are hoisted, draw would actually be defined at window.draw before the first line is run. So I'd thought of making window.draw a getter/setter so p5 could initiate top-level global mode as soon as the user defined draw but sadly that doesn't work.
But you seem to be suggesting a different idea, having p5 automatically put functions, that don't require a canvas, in the global scope. I like it but that could be tricky or impossible to implement in a way that's compatible with more advanced use cases, in which p5 is loaded alongside lots of other libraries, because automatically putting p5 functions on the global scope could cause functions with the same name to be overridden.
I didn't really mean to suggest a different implementation, but was thinking about what the user-facing feature it seems is being proposed here and may have understood. The common beginner issue I described—having errors invoking color() or random() in the global scope—sounded like it could be fixed by something described as "top-level global mode." If that's not the case, then I'm probably not interested in this proposal.
Assuming that we could teach students to always use
createCanvas(for 2D and WebGL non-ESM sketches) to load p5 before anything else, then we'd kinda get that "it just works" behavior on the top level for free, since users want to create a canvas at the beginning of most sketches anyway.
I'm not sure I'm following this. Would that mean that a default/skeleton sketch would then look like this?
createCanvas(400, 400);
function setup() {
}
function draw() {
background(220);
}
Thanks for the ping @quinton-ashley! This looks like a very interesting proposal. Since I currently have my hands full with a bunch of issues relating to p5.Vector, I haven't considered the discussion here fully, and I therefore can't advocate for any particular approach. However, I'll add a few points to the discussion that immediately jumped out at me, in response to this comment from @ksen0:
I think what would be most helpful is for other users (especially educators or people who recently learned p5.js) to weigh in.
Khan Academy precedent: A top-level global mode is used by Khan Academy's introduction to computer programming, via the older project ProcessingJS. On a personal note, that's actually the course that first introduced me to Processing/p5, and I found it to be a terrific introduction. A benefit of this approach is that it doesn't require beginners to be immediately faced with the concept of functions and function syntax. This isn't an insurmountable obstacle, but it's something to consider.
The Coding Train precedent: As a p5 learner, my next step after Khan Academy was to work through the excellent intro by @shiffman. You can see how he deals with being immediately faced with functions in the p5 web editor at 11:48 of the first substantive video; he doesn't actually get into the basics of functions until the 20th video.
Educator perspective: I can't comment on the consequences of early function syntax from a learner's perspective, as I had already programmed in several languages by the time I worked through the Khan Academy and Coding Train courses. However, as an educator [^1], I'd say that students are typically fairly comfortable overlooking details in the beginning, as in The Coding Train. I'd also say that, all else being equal, it's better if they don't have to, since it may cause confusion. In my own curriculum that introduces math learners to (vanilla) JavaScript, I do use the p5 web editor, but I start by instructing students to delete the function boilerplate that they don't yet understand.
Requiring beginners to confront variable scope:
I agree that having to declare variables at the top level, only to define them using p5 functions within setup(), will tend to cause confusion for beginners (as others with more p5 teaching experience have commented, including @kjhollen). This is an instance where asking students to overlook details may not work super well. While scoping can be explained, it's relatively advanced for an absolute beginner who is just learning the meaning of a variable. I think I can even remember a time when I was bitten by this detail myself, despite not coming to p5 as a programming beginner.
Neutral stance: To be clear, while this strikes me as a very interesting proposal that's worthy of discussion, I haven't yet had time to consider the details of the existing discussion. I also haven't yet considered the full ramifications of introducing top-level mode, e.g. on existing curricula like courses from The Coding Train, the p5 web editor boilerplate, and the p5 reference. So I'm not yet advocating for or against the proposal as a whole.
[^1]: To clarify, I have extensive experience as a math educator, and I generally follow the learning sciences, etc. I have some recent experience teaching programming, but my current experience in that specific domain is more limited.
The common beginner issue I described—having errors invoking
color()orrandom()in the global scope—sounded like it could be fixed by something described as "top-level global mode."
Yes that's the case!
The default sketch could be non-ESM with no functions, just like this.
createCanvas(400, 400);
background(220);
Or with a draw function:
createCanvas(400, 400);
function draw() {
background(220);
circle(mouseX, mouseY, 20);
}
async setup would be needed for loading.
But @davepagurek had an interesting idea of making p5.draw a setter, which would set the draw function on the p5 instance, that way users don't need to access the global p5 instance directly.
I actually really like the simplicity of this. This way we get top-level await in ESM and would never need an async setup function.
await createCanvas(400, 400);
p5.draw = function () {
background(220);
}
For webgpu:
await createCanvas(400, 400, WEBGPU);
p5.draw = function () {
background(220);
}
I thought about this more and it'd actually be possible to do this without breaking backwards compat if we only make the top-level createCanvas function return a promise. If createCanvas was used in async setup it could still return the renderer directly.
I'm going to try implementing this in q5 so you all can experiment with it!
@kjhollen this way users could do this:
await createCanvas(400, 400);
let r = random(1, 100)
p5.draw = function () {
background(r);
}
@GregStanton brings up another way this could be implemented is behind the scenes in the p5.js editor, that's how Processing does it too, the user's sketch gets converted to a Java class behind the scenes. But I'd much rather have this be a library level feature in p5.
I'd say that students are typically fairly comfortable overlooking details in the beginning, as in The Coding Train. I'd also say that, all else being equal, it's better if they don't have to
Yes exactly!
Hmm, I like the simplicity of being able to have a working sketch that's just
createCanvas(400, 400);
background(220);
Although, I think it is nice to have the simplest editor template include the function declarations for setup() and draw() because there's more syntax that a beginner has to remember and it's a good reminder. I usually need these functions by my second week of teaching when I introduce interactivity—I'd prefer to live with "delete everything to get started" the first week than to lose the reminders in the template for the rest of the class.
await createCanvas(400, 400);
p5.draw = function () {
background(220);
}
I'm not sure I see what this makes easier for beginners yet, because it opens more questions for me about how to teach this template. Does this imply the removal of setup() because JavaScript allows you to invoke code outside of functions? What does using p5. in the declaration of the draw function imply for beginners about how they should declare other functions? Would it then also be p5.mousePressed = function () { ... } etc. for built-in event handlers? Should they define custom functions for their sketch also starting with p5? What format would we prefer in documentation etc.?
I'd prefer to live with "delete everything to get started" the first week than to lose the reminders in the template for the rest of the class.
@kjhollen Yeah my thoughts exactly.
Does this imply the removal of
setup()because JavaScript allows you to invoke code outside of functions?
It allows for the removal of setup because top-level createCanvas would not just be responsible for creating the canvas but also loading p5, running p5 addons' async presetup hooks (if any), and putting all of p5's stuff (random, color, rect, etc.) into the global scope.
Running it in an ESM (aka JavaScript Module) enables top-level use of await, so we could load stuff outside of async setup.
What does using
p5.in the declaration of the draw function imply for beginners about how they should declare other functions? Would it then also bep5.mousePressed = function () { ... }etc. for built-in event handlers?
That's a good point. And yes but this would only be for ESM use. For non-ESM use users could still define functions normally.
For ESM use, yeah you could argue now we'd be missing out on using the setup and draw declarations as examples of how users could define their own function. But I also kind of like that there'd be an explicit distinction between definable p5 functions and user functions, instead of it just being magic.
Should they define custom functions for their sketch also starting with p5?
I'd say no.
What format would we prefer in documentation etc.?
That's a good question. Previously I considered ESM use to be too complex for beginners, but with @davepagurek 's suggestion it's gotten much simpler. Now I'm thinking that since p5 v2 already represents a big break from p5 v1, we could take the leap in the docs to ESM now cause that's where the JS ecosystem is heading.
But that could be a question we revisit later. For now my priority is just having this feature available in p5 v2 before next school year.
Here's three small demos!
- Classic script usage:
https://editor.p5js.org/quinton-ashley/sketches/kmDLLvSi8
- ESM usage:
https://editor.p5js.org/quinton-ashley/sketches/KS7FdQfpN
- ESM + WebGPU usage:
https://editor.p5js.org/quinton-ashley/sketches/wUcMy5cbd
Great. To be clear, I'm not advocating that we use ESM module syntax in default code for beginners and wanted to be sure that this feature proposal wasn't calling for that! I agree it's a little too advanced for that use case.
Can you clarify what the scope of this proposal is in the original issue? At the moment, I think we're conflating two features: 1) making it possible for beginners to call p5.js functions in the global scope and 2) ESM syntax for more advanced users. I can see how it's possible to solve both together with a clever implementation, but I think the purpose & audience is different enough for these two goals that they should be prioritized separately.
@kjhollen One option for the p5 docs would be:
- make all upcoming WebGPU docs use ESM top-level global mode
- use classic scripts (non-ESM) with top level global mode for the docs that use the default Canvas2D renderer and include async setup only when necessary for loading assets (ie. loadImage)
Can you clarify what the scope of this proposal is in the original issue?
The scope is broad so yeah it's a bit confusing that this one feature would have three distinct purposes.
The third purpose being a way to load WebGPU, which I think is good to include in this conversation because it's something that will need to be figured out soon anyway.
Perhaps it'd be best to split this into two or three separate issues? But I do think it's important to consider the broader scope here.
There are some technical considerations that make it a little hard to pull apart top-level global mode from ESM usage. In order to support any p5 addon, we have to be able to await somewhere in the setup of a sketch. If you await createCanvas(...) at the top of your sketch, that would work only in ESM sketches, as top-level await is only allowed there in JavaScript currently. If we allow usage of createCanvas without await (either inside or outside of ESM), then either users will have to be aware that some addons will break unless you await, which may also require switching to ESM. Another complication of switching to ESM is that we'd have to switch to a different way of setting up lifecycle functions like draw. A possible, heavier workaround to combine everything into one could be to create a <script type="p5"> where we do some transpilation before running the sketch, which is pretty feasible for e.g. the web editor, but complicates usage of p5 embedded into other places, like React or TypeScript.
Just sharing my own opinion here, but given that there are already changes to the core setup of p5 in 2.0, I'd push back on making a big update like this to the usage of p5 in documentation -- there's already a push for new education, and while there's value in removing the necessity for setup for sure, there's a very real benefit to having more unified learning resources that we'd be muddying with a change right now. Changing defaults for a future 3.0 would be another matter, and supporting this without changing all the learning resources is also a possibility.
If we were to support this just as an additional usage pattern, we'd mostly just have to investigate how easily we could support (and test!) both patterns to see if it's worth the maintenance of having both. I think that would be an interesting thing to look into, but this would probably be for an interested contributor to look at since it would, at least for now, just be for a small subset of p5 usage.
I am mainly interested in top-level global mode in the context of p5's upcoming WebGPU mode. Do you have an idea of when the initial version will be released? Will it be before September 2026?
I can't really give an answer there, it's not something p5 has a specific target for. It's likely that it'll live in a beta for a while too, at least until browser support is more widespread and less buggy.
If we go with the await createCanvas(200, 200, WEBGPU) way of loading, then it fits in with the current pattern where you have to await some stuff in setup, and also would help transition to a possible future (p5 3.0?) world where we do the work to make top level global mode work everywhere. I think it's unlikely that we'll have a special function to enable WebGPU since we imagine async canvas creation may be a problem other future renderers have, e.g. anything that needs to load wasm.
In order to support any p5 addon, we have to be able to await somewhere in the setup of a sketch.
@davepagurek Would that be the case for any addon or just addons with async presetup hooks?
If we allow usage of createCanvas without await (either inside or outside of ESM), then either users will have to be aware that some addons will break unless you await, which may also require switching to ESM.
True. But I think that'd be fine since such usage would mostly benefit beginners starting out with p5.js on its own.
For reference, I have a lot of short non-ESM top-level global examples here if anyone wants to see what this kind of documentation could look like: https://q5js.org/learn/?c2d=#canvasSection
hard to pull apart top-level global mode from ESM usage
Yeah my hands are tied here because q5play (p5play v4) needs to load WASM. I also want all its docs to use WebGPU with top level global mode, hence I'd to use ESM. Not so bad after your suggestion though!
Another complication of switching to ESM is that we'd have to switch to a different way of setting up lifecycle functions like draw.
What do you mean? I'm not familiar with this.
Changing defaults for a future 3.0 would be another matter, and supporting this without changing all the learning resources is also a possibility.
Thanks yes. I had assumed that it might be too late to make such big changes to p5 v2's documentation.
The transition could also be done more gradually during the lifetime of v2, if top-level global mode is implemented in a way that doesn't break compatibility, which I expect that it can.
Would that be the case for any addon or just addons with async presetup hooks?
Depends entirely on what the expectation is for using an addon. I lean towards doing it for all addons though. I'm less concerned about addons that introduce new renderers, because then at least the modification you have to make, adding await before createCanvas, is right next to the usage of the library. But adding await in that same spot because an addon internally needs to load something feels like something users would trip over often, and p5 is trying to move towards relying more heavily on addons in general (for a number of reasons -- reducing p5's github and release cycle as a bottleneck for features, more stability for addons that previously had to tap into undocumented internals, allowing smaller/more specific builds, etc), so I'm hesitant to add complexity there.
Another complication of switching to ESM is that we'd have to switch to a different way of setting up lifecycle functions like draw.
What do you mean? I'm not familiar with this.
Sorry, I just meant that rather than doing function draw() { ... } we have to ask users to do window.draw = ... or something else like that. Just another thing a user would have to change if they need to switch to ESM.
The transition could also be done more gradually during the lifetime of v2, if top-level global mode is implemented in a way that doesn't break compatibility, which I expect that it can.
I think a next step is for an interested contributor to experiment and see what size of change this would be and how testable it is. It's definitely possible in JavaScript to implement it to be compatible both ways, so I think the main question is how much of a maintenance load is it to have that in the codebase. That's a sort of hard question to answer in the abstract, and probably needs some time to look into before we can make a call on whether or not that's something possible to maintain in core.
But adding await in that same spot because an addon internally needs to load something feels like something users would trip over often
Idk about that, it'd be hard to miss if all the docs for an addon used await before createCanvas.
p5 is trying to move towards relying more heavily on addons in general (for a number of reasons -- reducing p5's github and release cycle as a bottleneck for features, more stability for addons that previously had to tap into undocumented internals, allowing smaller/more specific builds, etc)
That sounds great!
another thing a user would have to change if they need to switch to ESM.
Yeah but it's not so bad with your idea of setting on p5 which would already be in the global scope.
function draw() { ... }
p5.draw = function () { ... }