Closed evhan55 closed 10 years ago
i think it is a good idea @evhan55 P
could be deprecated one day but both versions can be supported.
concerning extensions, you can get 2 things with one single effort with the jquery-like extend approach: use the same interface to extend the prototype. then it's just a matter of choice: what you want to include in the public release, and what you prefer to provide as an external add-on.
// no more p5.prototype.whatever in the core but:
p5.extend({
line: function(a,b,c,d) {
...
},
PVector: function() {
...
}
});
others could do:
// write an app, that can also be used alone
function Kinect(){ .. }
// plug it in p5 to interact with a sketch
p5.extend({Kinect: Kinect});
I think a problem with Vector
and Image
is that they are such generic names they could conflict so easily with other libraries, frameworks, etc.
I'm interested in the fallout from the plugin/settings/instance/PVector discussion, but I am ok with name clashes in the JS namespace. I think at some point in JS name clashes are the name of the game, and I prefer clarity for beginners.
I'm interested in the ES6 discussion to help think about how PVector, PImage, PFont, etc, exist in the framework, too.
we should only think about the instance mode. the global mode would anyway be clashing with dozens of other possible frameworks/libraries names... color, line, point, etc are all common words.
in instance mode we only have one global variable, p5, so clashes are impossible. beginners would not use any other frameworks or libraries, i guess, and if they do, they would/should learn the instance mode. you could even add a plugin called Vector without problems, since it would just overwrite the original method or constructor. unless we forbid it (which is possible, by adding a simple check in the extend function: if the property name exists in the prototype just throw an error).
PVector can be supported and distributed as a standalone library, to be used without p5. actually the P, would make it easier to remember and to distinguish from others. (sorry for the long post!)
I see the arguments. Something still doesn't sit right with me to think of a collection of standalone classes meant for use with p5 that have the P
prefix. If they end up standalone like that, then perhaps they shouldn't be distributed with p5. Are there examples of other libraries that have 'standalone' classes that are meant to be used with the library? What are naming conventions like there?
For example, is there a game library out there, and what is their vector class like?
Here is one that imports vectors from another external library called Box2D: https://github.com/incompl/boxbox/blob/master/boxbox.js
In that case there is a whole physics engine library being used, not single classes, hmm. So are there any good examples of single classes being used with a library?
Hi all, I've been following this discussion closely but haven't weighed in as I'm still forming an opinion. I did look at a few other JS graphics libraries.
two.js
var vec = new Two.Vector(x, y);
three.js
var x = new THREE.something()
paper.js
var p = new Point(x, y);
so paper.js is saying Point, two.js says Two.Vector, three.js says THREE.Vector, but both of those two are intended to be namespaced under two or THREE in all cases.
this is just three examples of course...
These are so great to look at! Thank you Lauren!
Great references, look forward to hearing more of your thoughts!
I was thinking the same thing about PVector being cleaner as just Vector. But there is one clash that is problematic if this is extended to all classes: "Image" is a native javascript class that might be sketchy to overwrite?
I'm comfortable with the var v = p5.Vector()
syntax though. I think users will be comfortable with that by the time they get to directly instantiating those classes.
Ah, I can see var v = p5.Vector()
working well. Just as a point of clarification would it be var v = p5.Vector()
or var v = new p5.Vector()
or either?
Probably I'm totally out of scope but why the 5 in the name? You surely already thought and discussed about p.js or P.js but did not like it for some reason. I like these ideas to simplify names, and was thinking why using the 5 when we could further simplify the look of things like p.Vector()
or p.Image()
and the whole code by using p
.
(This is not very important maybe, I'll survive with the 5 too)
I'm not sure if you are asking why is the 5 there, or why should the 5 be kept. In the http://wiki.processing.org/w/FAQ it explains its origin:
“Proce55ing” is the spelling we originally used for the URL of the web site, because "Processing" was already taken. Even though it's a combination of numbers and letters, it was always pronounced “processing.” Since then, we saved our pennies, had a can drive, and used the funds to acquire the processing.org domain name. As a result we are no longer using the name “Proce55ing.”
When we see it with the 55's it annoys us and we want to punch people in the face. Or punch ourselves in the face for using it in the first place. Actually, we try not to be that emotional about it but we're trying to avoid the previous naming. However, to make it more confusing, we sometimes still use “p5” (but not p55!) as a shortened version of the name.
@taseenb we chose p5 for a number of reasons, some main ones being a reference to earlier proce55ing and also it being unique enough in this domain to google.
@shiffman so would it be var v = new p5.Vector()
in global mode or is this for instance mode? I guess the difference is that two.js and three.js have no global methods or classes so the syntax is like:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var scene = new THREE.scene();
var cube = new THREE.Mesh();
scene.add(cube);
so assuming you're speaking global, it would look like
var v;
var setup() {
createCanvas(200, 200);
v = new Vector(3,7);
}
and for instance mode would it look like:
var s = function(sketch) {
var g;
var v;
sketch.setup = function() {
g = sketch.createCanvas(200, 200);
v = new sketch.p5.Vector(3, 7);
};
sketch.draw = function() {
};
};
or were you thinking the p5.Vector() case was for instance mode and it would be just var v = new Vector();
for global?
@brysonian this is a good point about Image()
, @evhan55 thoughts around that one? would that need to be renamed completely? also do methods like createImage()
still make sense or should that be var img = new Image();
? I don't really mean to go changing up everything here if it's already working, but just asking questions...
@hamoid and @lmccart thank you for the explanation about the name.
@lmccart I like the way you have outlined possibilities for Vector()
in global and instance modes, if that makes sense behind the scenes (i.e. if JS supports that, which it looks like it could). One tiny nit, I'm not sure if it would be sketch.p5.Vector
or just sketch.Vector
.
I didn't realize the Image()
clash, interesting! I'm curious how other libraries handle that. Also, I'm still curious about the ES6 possibilities around this, I want to explore that a tiny bit, too, to see how much we are working ourselves into a style that will become outmoded right away.
Couldn't we always just leave it p5.Vector
? p5 is always around in the global namespace and it would certainly simplify teaching it if there was just one way to access the class. At least if we aren't injecting any dependencies (on the sketch instance for example), it feels cleaner to think of Vector as being a thing that is made available by p5, rather than something specific to a particular sketch.
ah, ok this sounds better to me. it felt weird to have the p5.
only sometimes. this could also help with the clash of Image()
. I like it conceptually, too. we understand it is a standalone class or module, but it's related to p5.
Agree! I think it might be nice if it could be var v = new p5.Vector()
as opposed to var v = p5.Vector()
for teaching clarity and emphasizing new
for creation of objects, but this may be way less important than I think it is.
I should also point out that Processing PVector is many years old and a product of a different time and set of constraints. The use of so many static methods, for example, is not typically what you see in more current vector implementations. For example, in Processing we say:
var c = PVector.add(a,b); // add two vectors together and get a new one
a.add(b); // add one vector to another modifying it
Whereas if you look at other vector implementations you might typically see
var c = a.add(b); // add two vectors together and get a new one
a.addSelf(b); // add one vector to another modifying it
Ooops, I think I am changing the subject too much and this should probably be its own thread. I guess the point I'm making is that if there were better ways to do vectors here in p5 we shouldn't feel tied to the PVector methodology.
yes, like the new. so classes that would change:
PVector >> p5.Vector()
PImage >> p5.Image()
PGraphics >> p5.Graphics() // not currently implemented
PFont >> p5.Font() // not currently implemented
PShape >> p5.Shape() // not currently implemented
PShader >> p5.Shader() // not currently implemented
is this correct?
currently, creating each of these differs. I think p5.Vector is the only one created with var v = new p5.Vector(2, 7)
while all others in Processing reference have a create or load method (var img = createImage();
). I think this is fine for now, just something to be aware of.
does this have @evhan55 approval? :)
Related to loadImage()
or createImage()
vs new p5.Image()
I think one original motivation for createX()
in Processing (in addition to having access to the PApplet) was to avoid the confusing OOP syntax for beginner beginners.
I'm starting to feel that this is less an issue here and in fact new p5.Thing()
could be more clear. That is certainly the case for advanced things like Vector or Shape. I am less certain about Image but ultimately I think getting a sense of objects from the start is not a bad thing.
I'm liking the namespacing of things under p5. Would this also hold for global mode? I think it could but want to make sure we would not be exporting these names to the global scope in that mode? (If we are exporting these to the global namespace in global mode, then I am extremely wary of overwriting an existing javascript built in like Image).
+1 to using new p5.Thing()
. I feel this is more consistent with how those entities are currently written. The Thing
is usually a constructor function so we should use new for consistency. With the createXXX being the convention for factories (maybe that is the convention plugins could eventually use for exposing factories). Now it maybe the case that the factories are eventually dropped if using the constructors directly works pedagogically for the various levels of processing user. As a side note, this set of issues made me look at PImage again and I realized it no longer actually uses the reference to a p5 instance anymore (I'm going to experiment with removing that code in a bit)
One specific comment on new p5.Image()
. There is currently a method on the processing instance for drawing images, called 'image()'. Might this be confused with the constructor for images? Compare new p5.Image()
and sketch.Image()
(which assumes you did not name your sketch p5).
To one of @evhan55's earlier questions about whether to think about PImage as a plugin or not. I think PImage should stay in the core and not be a plugin. PImage and the main drawing surface (the PGraphics equivalent) could share a lot of functionality (seeing as they are both canvas backed drawing surfaces) and could at some point allow them to be interchangeable in terms of a rendering target, allowing drawing to PImages and filtering/etc on the main canvas (which I think could be kinda cool and provide easy offscreen drawing/compositing).
@shiffman
What are your thoughts on PVector (or Vector) not being completely standalone anymore?
Given your comment here: https://github.com/lmccart/p5.js/issues/163#issuecomment-39126282
@lmccart What would this all look like in global mode?
It would be nice to unify all the object creation if that makes sense, so they are all new p5.something
and no factory methods unless they are needed for some reason I am not seeing right now.
@evhan55 I think the proposal is, in both global and instance mode creating a vector would look like var v = new p5.Vector(0, 0);
are you suggesting removing createCanvas()
, loadImage()
, etc?
I think it could be nice to keep them at least for the sake of those coming from Processing. also, we have been teaching with this for the past year and just made the change from createGraphics
to createCanvas
. I'm in favor of changing the underlying structure (ie p5.Object) and maybe supporting var x = new p5.Object()
for all, but I wouldn't want to be too hasty removing all the create and load methods.
I think @shiffman made the point that these were designed to shield the beginner from having to understand OOP from day one. it also looks a little weird to create an object without storing a pointer, in the case where you are creating a canvas and not calling it directly after that.
function setup() {
new Canvas(600,400);
}
@lmccart
I would want to argue for global mode to be truly global and to put the objects on the window. Even with the potential name clashes. (global p5 use is for teaching, and the teacher should know what the limitations are)
I don't see the point of having a global mode at all, then, if namespacing has to be used sometimes. This semi-global mode would be confusing, some of the p5 namespace would be global, but some parts would not?
For creation of these objects and factories, I don't feel as strongly as to which have convenience methods and which don't. But it'd be nice if there were a clean story re: objects that come with p5.
What are the objects available? How do I make one?
I can see it being confusing if there are two things:
The distinction there isn't very strong to me, and is confusing, and not a very clean design, I think.
@tafsiri
Re: "One specific comment on new p5.Image(). There is currently a method on the processing instance for drawing images, called 'image()'. Might this be confused with the constructor for images? Compare new p5.Image() and sketch.Image() (which assumes you did not name your sketch p5)."
Yes exactly, I agree that the confusion is possible, and I would want to revisit these functions/creators from the Processing API and make sure whatever we bring over is clean and consistent with whatever constructors we add on top.
@evhan55 ok, I'd be alright with new Object()
instead of new p5.Object()
for global, but won't overwriting Image()
break our p5.Image / PImage implementation? https://github.com/lmccart/p5.js/blob/master/dist/p5.js#L1352
maybe Image needs to be something else then. I don't know what.
ok, here is the proposal @evhan55 and I put forth:
PElement >> Element()
PVector >> Vector()
PImage >> Image()
PGraphics >> Graphics() // not currently implemented
PFont >> Font() // not currently implemented
PShape >> Shape() // not currently implemented
PShader >> Shader() // not currently implemented
we will keep the constructors for these as are, in both global and instance. typically, create is used to create an empty version of something, load is used to create something from a file:
var img;
function setup() {
createCanvas(100, 100);
img = loadImage("cat.jpg");
}
var s = function(sketch) {
var img;
sketch.setup = function() {
sketch.createCanvas(200, 200);
img = sketch.loadImage("cat.jpg");
};
};
var myp5 = new p5(s);
now for vector, there are two options.
option 1: vector is treated as a special plugin. functionally, it works the same, this is mostly a philosophical distinction, with small syntax and organizational effects. our thinking is, while image, element, etc seem pretty crucial to the core experience, vector is a data type. why is it the only data type, should there be more, where do we stop adding to the core? if we treat this as a plugin, it's distinguishes it as slightly separate, and leaves room for more data type classes like this. by special we mean, rather than this being hosted and maintained separately, Vector would be documented and ship with the core p5 library, and have unit tests included, too. however, rather than going in src/
it would be in a folder plugins/
.
initialization would remain the same:
var v;
function setup() {
createCanvas(100, 100);
v = new Vector(0, 0);
}
var s = function(sketch) {
var v;
sketch.setup = function() {
sketch.createCanvas(200, 200);
v = new sketch.Vector(0, 0);
};
};
var myp5 = new p5(s);
option 2: vector is part of core. functionally, it works the same, but placed in src/
and treated as such. if this is the case, we feel it should also have a creation function like var v = createVector(0, 0);
to match the other core classes.
@shiffman we are curious what you think regarding the options. essentially, it comes down to making a conceptual decision rather than a lot of change code-wise.
Image()
clash may pose a problem, but it is not really called explicitly by the user, so we could rename that one internally to preserve functionality. to be resolved.
Just to clarify, with the non createVector()
option, i.e. var v = new Vector(0, 0);
do we still have the problem of Vector having no internal knowledge of the p5 sketch instance and therefore needing to receive this
to deal with angleMode
or random seeding?
I think I prefer v = new Vector(0,0);
over v = createVector(0,0);
but that may just be b/c I'm so used to v = new PVector()
in Processing.
@shiffman I believe, as a plugin attached to the instance, it should have access, but that is a hunch.
If you prefer the plugin route, we will try it! We'd be excited to try that for Vector, and I think we are going to make a new development branch to start making these large changes, so master stays stable for the spring class.
Great, one note I'll make is that I definitely prefer v = createVector(0,0);
over v = Vector(0,0);
. I think it's good to try to be consistent about new Object()
and createObject()
.
hi @shiffman concerning the instance reference within PVector (or Vector), you'll need to pass it as an argument if you use new
, but you can get it implicitly if you use a function like createVector()
just a comment. since John Resig is interested in p5, i feel right if i take inspiration from his experience (jquery has a lot of success with beginners and people learning how to program). jquery uses many aliases and different syntax options to do the same thing: i don't know if this is a good practice in general, but that works very well and allows an expressive use of that library and javascript. with time, people discover that those syntax variations can have a meaning and sometimes be used to achieve different things. syntax flexibility allows jquery to adapt to the user's style or to a particular situation, more than the opposite. a classic of the jquery syntax:
// one of the first things a beginner generally learns:
$( '#selector' ).click( // do something );
// that is an alias for:
$( '#selector' ).on( 'click', // do something );
// and also for the now deprecated bind method:
$( '#selector' ).bind( 'click', // do something );
// also for a more advanced use, the event delegation:
$( document ).on( 'click', '#selector', // do something );
// alias for a now deprecated delegate method:
$( document ).delegate( '#selector', 'click', // do something );
// the same method can also work as a trigger
$( '#selector' ).click();
$( '#selector' ).trigger( 'click' );
you can probably have more than one way to create a vector, like:
var v = new p5.PVector(x, y, z, instance); // to be deprecated
var v = new p5.Vector(x, y, z, instance);
var v = createPVector(x, y, z); // to be deprecated
var v = createVector(x, y, z);
var v = PVector(x, y, z); // to be deprecated
var v1 = Vector(x, y, z);
var v2 = Vector(x, y, z).add(x,y,z).sub(v1);
etc.
@shiffman
Just to clarify, in one comment you said:
"I think I prefer v = new Vector(0,0);
over v = createVector(0,0);
"
And in another comment you said:
"I definitely prefer v = createVector(0,0);
over v = Vector(0,0);
"
Is there a typo or did I misread either comment?
I think my take away is that your preference is for Vector
to be a plugin and be instantiated with Vector()
, is that right?
I think he's just saying the preference is to have new
in there. so let's try vector as plugin instantiated by var v = new Vector();
?
@taseenb
The proposal is for p5 to have some core classes like Image, Shader, etc.
Those will be instantiated with convenience createXYZ()
methods.
Then, p5 will also have plugins that are added onto p5 and only accessed via 'new XYZ()
.
We will not support p5-namespaced createXYZ()
methods for plugins, plugins are meant to be independent with their own set of methods under their own namespace (accessed via p5).
If plugins want to support their own convenience methods, that is out of our design and totally possible. Flexibility is good, yes!
For the core p5 we want to start with a clean API first, and think about overloading a bit after things have solidified, for the sake of clarity and beginners. What does @lmccart think?
@lmccart
Oh, I see! Yes, that sounds good!
@evhan55 yes!
@evhan55 sure, sorry if i created confusion! but it seemed to me that the problem was also how to get the instance, or that's already solved? with new
the user will have to pass it as an argument.
This is, interestingly, exactly the same approach as Processing. For example, core classes are created with createObject()
i.e.
PImage img = createImage(w,h,RGB);
Libraries (similar I think to the "plug-in" idea) are done with new
, i.e.
Capture c = new Capture(this,w,h,frameRate);
PVector is the one exception since it doesn't really need access to the PApplet instance:
PVector v = new PVector(x,y,z);
It sounds like the most recent p5 proposal is the same. The one difference is that with p5, due to angleMode, Vector
does require access to the instance. Will it also need to be. . .
var v = createVector(x,y,z);
. . . ?
Or would it be:
var v = new Vector(x,y,z);
unless the user decided that angleMode mattered and therefore says. . .
var v = new Vector(this,x,y,z);
. . ?
Am I understanding all the scenarios correctly?
@shiffman I think we would like it to be
var v = new Vector(x, y, z);
but it seems like because it needs access it would need to be a variation like
var v = new Vector(this, x, y, z);
for including a library like Capture for example, it makes sense to me to include the this
reference, but for something like Vector that you might think of as smaller, lighter, it feels clunky to have to pass in this
. maybe this is a reason to keep it part of the core and just add the createVector()
method?
I agree. I think the alternative (which I am also ok with) is just to say that Vector doesn't know about angleMode and it's your job to call degrees()
if you need to. I definitely prefer createVector()
over new Vector(this,x,y,z)
.
We could also allow either, but if you make a vector this way new Vector(x,y,z)
that's a radians only vector.
ok, so sounds like there are three options:
createVector(x,y,z)
-- vector class is thought of as part of core and has an associated create method like all other classes (createImage, etc)var v = new Vector(this,x,y,z)
-- and vector is thought of more like an addon that ships with corevar v = new Vector(x,y,z)
-- does not take angleMode into considerationmy vote would be for option 1. @evhan55 and I discussed last week and felt @shiffman you use vector more than us so we would defer to whichever preference you had, sounds from above like you are voting for option 1 as well, but let us know if you'd prefer to go with 3 and have it be radians only.
I think Option 1 makes the most sense!
I am not sure if this is a terrible idea or not, but I might allow all three but have all the examples and documentation use 1. In other words, vectors will work without a reference to a p5 sketch instance and just default to radians. and createVector()
just does option 2 for you behind the scenes.
ok, I have implemented options 1 and 3, but not 2, because calling var v = new Vector(this, x, y, z)
in the context of a sketch doesn't give the proper reference to p5 right now. something to be resolved with libraries in general later, but for now we're good with createVector(x,y,z)
which accounts for angleMode and var v = new Vector(x,y,z)
which is radians only (but not recommended in documentation).
@shiffman I started to take a stab at modifying pvector to account for angleMode if it has a pointer to the p5 instance, but I started feeling shaky about which way things get converted. I tried one here: https://github.com/lmccart/p5.js/blob/75b0c18e2f3af1cdb09d928a55577eda39c5d5af/src/math/pvector.js#L306
I can keep going with this, or if you'd prefer to do it, you could follow the pattern in the example I did (first check for reference to p5 instance with this.p5
, then check angle mode this.p5.settings.angleMode
, otherwise assumed its radians only). let me know!
Looks like what you did is right and I'm happy to take a crack at finishing it up. Will submit a pull request soon!
closed with commit 998d20ef97c9a9f29aea675bf27a47c04a5e7a41
@shiffman @lmccart
I am very excited about thinking of
PVector
as a pseudo-plugin for p5, given that it is a completely independent object type.A potentially divisive question, but just wanted to throw it out there:
I would be happier calling them
Vector
andImage
rather thanPVector
andPImage
, is it possible/acceptable to think about a Processing compatibility layer that knows to acceptPVector
etc. for people who are coming from Processing, but that is not what is taught "out of the box" with `p5'?PVector
andPImage
feel heavy and confusing (the P is capitalized but not in p5, so the link isn't very strong there for me).Vector
andImage
feel better to me.And do we want to think about
PVector
/Vector
andPImage
/Image
as plugins, or no? Currently, they are not being included in a very clean way, and I think it's worth thinking about as we continue.