Initially this was supposed to be a quick post on a bunch of useful tricks to shorten the javascript code of your #つぶやきProcessing sketches. However, I really needed to dig into and research some points on my list, because I wasn't 100% sure how certain things actually worked! This made the post end up being a list of 10 #つぶやきProcessing tips, each of which is a tiny javascript lesson.
What's #つぶやきProcessing?
#つぶやきProcessing, pronounced Tsu-bu-ya-ki processing, literally translated meaning 'Tweet Processing', is a Twitter specific code golfing challenge, where you try to fit a compilable and functioning piece of P5 or processing code into a single tweet. Generally these tweets are also posted alongside the graphics that they generate.
This 280 character sized challenge first emerged with Japanese twitter user Hau-kun in 2019:
He says as much as:
I'm going to create a tag #TweetProcessing out of the blue!
And in the replies he elaborates that he had been previously trying to make a rainbow sketch within the 140 character limit, and that the character limit increase had given him a lot more flexibility. And it genuinely seems tough to make anything interesting within 140 characters. Hau-kun then started tweeting many #つぶやきProcessing sketches over the course of the next months. Fast forward a bit, and lots of folks started joining in before the hashtag started to take on a life of it's own:
Hence, let's have a closer look at some tips to get you started with #つぶやきProcessing! Enjoy, it's a fun one! Here's the index:
The Tips:
- Expression return values
- Omitting the draw and setup functions
- Storing functions in variables
- Arrow functions
- The conditional ternary operator
- Skipping last condition in a for loop
- Code inside the for loop
- Multiplying a condition
- Multiple assignment with an array
- Putting it all together
Expression return values
Let's start off with a tip that will come in handy in each and every one of your #つぶやきProcessing sketches! Drawing anything to the canvas requires creating it first. Since we're short for characters, we most likely don't have the luxury to make a sketch that adjusts to the window dimensions. For this reason most #つぶやきProcessing are created with a fixed canvas size:
function setup(){
w = 600;
createCanvas(w, w);
}
This first trick involves placing the declaration of the canvas size within the createCanvas() function, like so:
createCanvas(w=600,w);
Essentially we're assigning a value to the variable 'w' AND immediately reusing it as a second parameter for the createCanvas() function... now why does this work? It has to do with what is considered an expression and what is considered a statement in javascript:
// this works because w = 600 is an expression
createCanvas(w=600,w);
// this doesn't work because var w = 600 is a statement
createCanvas(var w=600,w);
In general, expressions in javascript are units of code that can be evaluated to a value. Here the assignment is in fact an expression, which will return the value that was assigned. And this is by design. It also enables things like multiple assignment, for example:
a = x = y = 5;
Which could also be a useful trick to save you some characters. More on this here.
Omitting the draw and setup functions
We generally structure our p5 sketches to have a setup function, where we do some preliminary things, and then draw our graphics in the draw loop which runs after the setup function has finished. However it is not always necessary to have both the setup and draw function. When we're simply dealing with a static image we don't require the draw function at all, and could simply write our code at the end of the setup function. This would also lets us make do without the noLoop() function call.
On the other hand we could also omit the setup function, which is a little tricky because we still need to create the canvas, and the createCanvas() function should generally only be called once. A nifty trick for this is:
f=0;
function draw(){
f++||createCanvas(w=600,w);
}
Neat right?! On the very first draw call the expression 'f++' returns 0, which forces the sketch to check the second part of the condition, which in turn will actually create the canvas. On subsequent loops of the draw function the variable f will have been incremented, which means that it doesn't actually have to check the second part of the condition anymore. This is because values other than 0 are considered to be truthy.
Storing functions in variables
Another nifty thing we can do to save on characters is replacing a function's name with one that is shorter. This is useful when you're using some inbuilt p5 functions that have a somewhat lengthy name, for example:
// let's shorten the random() function
// and store a reference to the random function in a variable
R = random
// we can now use the shortened version
func(R(), R())
This is another trick that had me scratching my head! I get what's happening, but why is it possible?! For this we have to have a closer look at how javascript works internally. I asked the folks in the birbsnest discord and Julien Pradet explained it very elegantly:
So when you do function draw() { }, what you actually do is storing the draw function in a variable called draw. It's done automatically. But you could also write: let draw = function draw() { }. draw() would still behave the same way.
And also provided a nice example:
// This exists inside p5 even if it's not written this way
let random = function random() { /* ... */ }
// in your code
let R = random; // in a sense, you're just copying the function into another variable
R(); // outputs the result of the `random`
In conclusion he also adds:
[...] but beware, you're dangerously close from entering the world of functional programming. In no time, you'll be creating functions that return functions, want to curry all your functions and so on. (I'm personally in love with this way of writing code.)
So there's that, go show Julien some love, he makes some cool gen-art and streams live coding on twitch every monday and saturday. Also join the birbsnest, it's a lovely community.
Arrow functions
On the topic of functions, that 'function' keyword takes up an awfully large number of characters. We can do better here as well and save some characters by using arrow functions! Arrow functions are a javascript feature that has been introduced with ES6, and for our purposes enable a much more compact way to write function signatures:
// instead of doing this
function someFunc(a, b){
return a + b
}
// we can omit the 'function' keyword and the name of the function
// and rewrite it in this manner by using the arrow function expression
(a, b) => {
return a + b
}
// we can further reduce this by removing the curly braces
// and the return keyword
(a, b) => a + b
// to use this we can assign this arrow function to a variable
let someFunc = (a, b) => a + b
// which can then be called in this manner
someFunc(a, b)
Ok a lot is happening here. Basically, arrow functions let us do without the 'function' keyword as well as the actual name of the function, instead we just specify what kind of arguments it should take, followed by the arrow symbol (equal and larger than symbols) pointing towards the body of the function. We can now also omit the curly braces, which tells js that the value following the arrow should be returned. In that way we can also omit the 'return' keyword. Now we can use this to shorten the signature lines of our setup and draw functions, ending up with something like this:
setup=()=>{createCanvas(w=600,w)}
Since the setup function doesn't take any paramteres, we can make it a parameterless arrow function by writing it with empty parentheses. However, we can make it even shorter, by declaring it such that it actually takes in a parameter, so you'll often see something like this:
setup=_=>{createCanvas(w=600,w)}
Now we could technically pass in an argument to the setup function, but the setup function is usually never called a second time from within the code, so it doesn't matter, and it saves us a character.
Ternary conditional operator
Conditional statements are also very useful and often needed to make interesting sketches. if/else statements however quickly add up to a significant amount of characters that we could save by employing the ternary operator:
// regular if else statement
if(condition) {
func1()
}else{
func2
}
// the ternary operator
condition ? func1() : func2();
It's pretty straightforward actually, the condition goes before the question mark symbol, the first option after, followed by the second condition separated by a colon. We can also obtain more complicated logic by chaining them:
// multiple ternary operators chained together
condition ? func1() : condition2 ? func2() : func3();
Notice how we can also skip the parentheses around the condition! Another thing I want to add here is that the curly braces are not always necessary, hence if for some reason you need to use an if statement, you can do it like this:
if(condition) doSomething();
I personally don't like it, but it's a possibility.
Skipping last condition in the for loop
A for loop formally consists of three parts: an initializer, a termination condition and an iterator. In most cases we can actually make do without the third part:
// regular for loop
for(let i = 0; i < 10; i++){}
// rewritten and shortened
for(let i = 10; i--;){}
In this case we reversed the iteration order, counting down from ten rather than starting from 0. Why does this loop actually terminate? After completing ten iterations the variable will reach a point where it is equal to zero, in that case the for loop will check the condition and determine that it is false. Thus it will stop looping. I'm sure there are other creative ways to make use of this as well!
Code inside the for loop
Moreover, we can make use of the fact the initialization clause in the for loop only gets executed once, and the iteration clause several times. As a matter of fact, the for loop doesn't really care what you write inside of it. As long as you still fulfill the termination condition you should be fine. Let's have a look at an example:
f=0;
draw =_=> {
for(
f++ || createCanvas(w = 600, w),
background(220),
maxNum = 10,
spacing = w/maxNum,
n = 0;
n < maxNum;
rect(n++*spacing,
(n-1)*spacing,
spacing,
spacing
)
);
}
This would simply draw a couple of rectangles along the diagonal. All of our setup stuff went inside the first clause of the for loop! You just need to make sure that these statements are comma separated, the last of which terminated with a semin-colon. Then we have the termination condition, as well as the iteration clause. We are actually drawing the rectangles inside this clause, and incrementing the loop variable 'n' inside of it. Remember that an expression returns it's value? Throwing all of this together we can achieve some pretty interesting stuff, here's a sketch where I use this technique and a bunch of the previous ones:
Due to having a fixed canvas size you might have to copy it into the p5js editor to see it as intended. And credit where redit's due, putting code in the for loop I stumbled across through Maxim's awesome video on Tsubuyaki Processing tricks:
Seriously go check it out, it's a really good video where goes over a number of sketches. All of which have some interesting tips and tricks!
Multiplying conditions
Another thing that comes in handy very often, is the ability to multiply conditional expressions with numbers. This is often useful when doing combinatoions and permutations of things. Let's have a look at how this works:
for(let i = 0; i < 10; i++){
console.log( 5 * ( i % 2 == 0 ) )
}
In this example the loop will print 5 when i is odd and 0 when i is even. This is because the boolean expression (i%2==0) when truthy evaluates to 1 and when falsy evaluates to 0. This came in incredibly useful when I did this recursive grid sketch:
Multiple assignment with an array
Last but not least, here's another trick to assign multiple different values to several variables. This is sometimes useful when we create variables with the 'var' or 'let' keywords and don't want to declare them with a global scope. We've already seen that we can assign the same value to multiple variables like so:
// assign a value to several variables
var a = b = c = 5
However what if we want to assign different values to different values, can it be done in a single line? Yes, it can:
// we're going to use an array for this
var [a, b, c] = [1,2,3]
// and now we can simply use these variables by themselves
var d = a + b + c
This way of assigning values is also a feature of ES6 and is called array destructuring.
Putting it all together
And finally here's a sketch where I combine a lot of these techniques that we've discussed today:
And here we find ourselves at the bottom of the blog post again! If you've enjoyed the post, share it with your friend, it helps out a lot! Otherwise come say hello on Twitter! Thanks for reading and happy sketching!