-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Namespaced mode #7332
Comments
I think p5 instance mode already lets you do that pretty much: https://editor.p5js.org/davepagurek/sketches/RLPK_J382 The one difference is that it seems to require that you pass a function into the p5 constructor currently, even if it's empty. So maybe the only thing needed to get what you're describing is the ability to use the p5 constructor with no arguments, with the expectation that it will be assigned manually afterwards? |
Thanks @davepagurek, this is great. I didn't realize you could define Would this still work in a modular architecture though? If we imagine this code split into 2 modules This is of course assuming p5 v2.0 will support ESM. Please correct me if I'm wrong. |
That's true, but also is a problem in q5.js too -- you still would have to give the namespace/instance to the class somehow if it isn't able to grab it from the local scope. A kind of hack you could use is to declare an empty local variable in the let p5 = undefined
class Rectangle {
draw() {
p5.fill(255);
p5.rect(50, 50, 50, 50);
}
}
Rectangle.setup = function(instance) {
p5 = instance;
}; and then in your main sketch: import { Rectangle } from './Rectangle.mjs';
let q5 = new p5(() => {});
Rectangle.setup(q5); // Pass in the instance here
let rectangle;
q5.setup = function(){
q5.createCanvas(100,100);
rectangle = new Rectangle();
}
q5.draw = function(){
q5.background(0);
rectangle.draw();
} or, to make one global namespace, have a file like this: export const q5 = new p5(() => {}); and then import that in all your other files: import { q5 } from './global.mjs'
class Rectangle {
draw() {
q5.fill(255);
q5.rect(50, 50, 50, 50);
}
} import { q5 } from './global.mjs'
import { Rectangle } from './Rectangle.mjs';
let rectangle;
q5.setup = function(){
q5.createCanvas(100,100);
rectangle = new Rectangle();
}
q5.draw = function(){
q5.background(0);
rectangle.draw();
} |
@araid 2.0 will support ESM and due to the nature of ESM, sketches have to be written in instance mode. The way we are testing and iterating in 2.0 development is using an ESM sketch. I would recommend the |
Thanks, this all makes sense. @davepagurek the solution of creating the sketch in a global file seems the closest to what I'm proposing. @limzykenneth imho there's a difference in terms of readability and being able to reuse modules, between the current "instance mode" and a potential "namespaced" or "library" mode:
import GUI from 'lil-gui';
import Stats from './lib/stats.module.js';
// import p5 from 'p5'; // ideally
class Rectangle {
constructor(p5) { // currently
this.p5 = p5;
}
... I still believe supporting this architecture would be valuable to people looking to integrate p5.js in larger apps along other libraries, but I'm not familiar enough with the codebase to estimate the complexity of building it. I'd love for the feature to be considered for 2.0 but feel free to close the issue if it doesn't sound feasible. Thanks again! |
@limzykenneth I think we don't actually need anything too heavy to support this. I think to fully allow sketches to be declared outside of a sketch callback in instance mode, we'd need to:
|
The existing mechanics is that to defer global mode initialization
This I feel have a bit too much assumption in that it only works as part of a script tag include, not with ESM. It's also a bit hard to know how much to defer initialization if for example the user code attaches to setup and draw aynchronously. @araid For Three.js they work quite differently from p5.js in that Three.js does not provide a runtime and so they don't have an initialization, meaning it doesn't matter the order in which things are defined for the most part, also they use a very different mostly OOP based API whereas p5.js are almost entirely procedural. The syntax @davepagurek suggested will work if you wish to expose the p5 instance to the environment instead of having it be owned by the object, it is just my opinion that attaching the instance as a class member is the better approach in terms of reusability and flexibility.
|
@davepagurek Thinking out loud a bit, I think what we can do/look into instead if we want to enable something like namespaced mode, we can look into the initialization step in In ESM instance mode, |
We make the following assumptions for anyone wishing to use namespace mode:
A potential way going back to @davepagurek's suggestion of const repeatUntilInit = () => {
if(this.setup) {
this._start();
}else{
setTimeout(repeatUntilInit);
}
}
repeatUntilInit(); Not sure if this breaks anything though. |
I guess we already don't support asynchronously attaching setup/draw in the currently recommended initialization, right? const sketch = new p5(async (p) => {
await new Promise((res) => setTimeout(res, 5000))
p.setup = () => p.createCanvas(200, 200)
p.draw = () => p.background('red')
}) Given that, I think it's not too much of a stretch to tell users that if they want to add setup/draw externally, it would also need to be done synchronously after construction, but I guess that means just doing
That looks like it could work, or also assigning setters on the class p5 {
// ...
set setup(cb) {
this._setup = cb
this.start()
}
} ...or one other option is to just expose a |
I like the setter option but it may have problem where setup is defined and the runtime start but draw is not yet defined. We can try to add a Calling a I can look into the code and implementation after I'm done with the refactoring but in any case the priority is to make sure global mode, instance mode, and possibly defer global mode we currently have work the same way otherwise we could be breaking a huge amount of existing tutorials out there. |
Makes sense! Yeah I consider this mostly a nice-to-have if we've got time |
Increasing access
unsure
Most appropriate sub-area of p5.js?
Feature request details
The current global and instance modes are not ideal for integrating p5 into larger web applications:
sketch
object to every class that wants to use the p5 library, making the code more complex.It would be great for 2.0 to add a third instantiation mode that's more in line with how THREE, Babylon or other libraries work.
In this mode, p5 functions would be neatly contained in a single global object, getting us closer to the modular approach that's already underway. Lingdong explains it very well in his q5xjs library.
So instead of doing this:
we would do this:
which seems like a very small gain but can lead to much more readable code as the application grows.
The text was updated successfully, but these errors were encountered: