P5.js is for writing software to make images, animations, and interactions. The idea is to write a single line of code, and have a circle show up on the screen. Add a few more lines of code, and the circle follows the mouse. Another line of code, and the circle changes color when the mouse is pressed. We call this sketching with code. This site introduces tools, methods, and concepts related to creating computational form, algorithmic images, generative art, procedurally generated content, and parametric designs. Hello p5js blocks This is the canonical p5.js 'Make Circles' sketch formatted as a p5.js block. Useful as a starting point to fork and customize.
In this post, I’ll discuss my approach to prioritizing work in open source software projects. I’ve found that aligning my work with the unique intent of the project has helped me feel more satisfied with the impact of my open source contributions. I’ll share some questions to help you get started on developing your understanding of an open source project’s intent and include some examples of how to put them into practice.
Every open source software project is different. Not only in their tech stack, but also in their intent. Sometimes I focus so much on widely used projects (like React) that I forget about the wide range of intents available to an open source project. As I’ve been getting more involved as a maintainer on p5.js this year, I’ve had to think a lot about what makes p5.js unique.
p5.js is unique in that it:
- is a browser-based creative coding library
- is heavily involved in events like Processing Community Day and the p5.js Contributors Conference
- has its own online editor
But what makes it unique for someone working in the GitHub repository? How is working on p5.js different than working on React?
Getting more involved
At the beginning of this year I received a year-long fellowship from the Processing Foundation to work on p5.js for a few hours each week. The constraints on my involvement were loose—I could determine the focus of my work, with guidance from Lauren McCarthy.
I made the argument (mostly to myself) that updating the build tooling could make that part of the codebase more approachable and maintainable for other contributors. And it could support some different packaging standards, which would make it easier for developers using Webpack (and the like) to include p5.js in their projects.
In retrospect, I realize I also wanted to show that I could do some “serious” technical work on the project. Updating an older build system dependency to something more current felt like an unequivocally good (and therefore safe) task to undertake. I felt I could comfortably say “you’re welcome” after it was finished.
I have been reflecting on this impulse to seek out “serious” technical tasks and where it comes from a lot this year. When I was working as a UX Designer at Linksys, I remember feeling like I wasn’t technical enough even though my role had no technical deliverables. I felt like I was “wasting” my potential as a tech worker by not maintaining a technical focus. Selling myself short, so to speak. It took me six months to (mostly) let go of that feeling and focus on the work I had signed up to do. I learned so much about iterating on design details and utilizing regular usability tests.
I think my desire to invest in “technically impressive” tasks comes from a similar place. And this is all fine by itself, but when I put that into the context of what I could be working on instead, I feel suspicious.
Iterating on the p5.js build system
I tried out a couple different build tools and solicited feedback from other contributors to p5.js. I wanted to be sure others were on board for this work and that overhauling the build tooling would result in something better for us, not just different. We settled on Parcel, primarily for its approachable API and the minimal configuration it would require.
However, after investing a decent amount of hours in this build tooling overhaul I abandoned the effort. Parcel had a limitation with its Babel integration that made it unusable for p5.js. Even more unfortunately, we only caught this in the final code review.
My understanding is that the forthcoming Parcel 2 will address our use case, but the timeline for its release is unclear.
We decided to keep the existing build system and I’ve helped maintain it since. I made a couple adjustments to facilitate our transition to ES6, but there haven’t been any major problems. Afterwards I wondered, what if I had succeeded in the overhaul? Would the result have been that much better? Would it have been worth the time and effort?
I think it would have been better, but not worth the time and effort, especially when I put it in context with what I else I could have focused on during that time. I could have found new ways to integrate the project’s linter into our workflow (besides a pre-commit Git hook). I also could have worked on increasing the contextual awareness of p5.js’s errors so that it could give even more helpful warnings and advice.
I think any of these could have been better uses of my time and energy. They were (and are) both technical opportunities and project opportunities. This is the trap with 'purely technical' thinking: losing the context in which it exists. At its worst, it permits us to build useless (or oppressive) things.
I don’t think my work on the build system was fully aligned with the intent of p5.js. To be fair, I hadn’t realized that at the time. Figuring that out has brought some clarity to my work. This isn’t to say I’m a lawn mower of open source development, churning through tasks on a regular schedule. I’m distractible and occasionally susceptible to technical rabbit holes, but I’m getting better at pulling myself out.
Open source at differing scales
Intent is one of the most fundamental differences between projects like p5.js and projects like React. Large corporate-backed frameworks are meant to support their company’s tech needs, but they are also meant to scale as much as possible.
p5.js (and other projects like it) aren’t trying to scale unbounded. Over time I’ve come to believe the most important part of p5.js is accessibility (defined in the broadest sense). Specifically, access for marginalized groups that often have significantly less access to technical tools and knowledge.
A successful feature ship for p5.js isn’t supporting a new use case or incorporating a new browser API. It’s the (often unglamorous) work of translating documentation, adding new tutorials, writing friendlier errors, and improving compatibility with screenreaders. The goal is not to be technically impressive or to be as popular as possible. It’s to connect to other members of other communities, invite them in, ask them what they think, what they would change, and help them pursue that if they want to (whether it’s in our project or in their own space).
It’s hugely important to understand the intent of each open source project you contribute to. It’s easy to treat a project like a generic open source project but that brings many assumptions. Again, relatively few projects can reach the scale of React, and even fewer need to. There's plenty of other ways to focus a project.
Here’s a few questions to ask yourself:
- What makes this project unique?
- Why was it started?
- Why do people use it? (If it’s a new project, why would people start to use it?)
- Why don’t they use other projects (or some other approach)? (If it’s a new project, why do people use other projects or approaches?)
- If this project could only do one thing, what would it do?
- Who is this project for, in the most specific terms possible?
- Who isn’t this project for, or who isn’t the focus?
Somewhere in the answers to these questions, you’ll start to see themes and connections. Some of these questions will likely require some research to answer. A narrative might take shape for your project or the people who use it.
Sometimes when I answer these questions I feel bored, but I’ve learned that usually indicates I don’t know enough about the project and its users to have a helpful answer. One of the best ways to break out of this is to talk to someone who works with the project and ask them questions about it! Be curious and get specific.
Once you’ve got something of a handle on these, you can start implementing some boundaries in maintenance of the project. A common example of this is setting expectations around response times to posts on GitHub. Some projects are hungry for outside contributions and it's critical to have quick responses from maintainers to keep momentum up and unblock contributors. For others the time that communication would take outweighs the work that can be done by the maintainers themselves.
The expectations for your project are driven mostly by resources and (unsurprisingly) the intent of the project. When I was working on funnel, I open sourced it for transparency and as a reference for others building GitHub Apps with Elixir and Phoenix. As such, I didn't put a lot of effort into engaging contributors outside of Carbon Five (where I worked at the time). However, I did spend time on documentation, tests, and type definitions since those would be more directly helpful for my intended audience.
As a current maintainer of GitHub Desktop, I spend much more time cultivating and encouraging external contributors. Part of the project's intent is to engage with the larger open source community.
Regardless of your project's approach, it's hard for outside contributors to know what kind of timescale the project operates on unless the maintainers tell them. Contributors can have wildly different ideas of what's a reasonable response time due to their own availability, cultural norms, and experience with other projects.
P5 Js Button
Here's a few ways to communicate what they can expect from you:
- create a contributing guide
- messages from a welcome bot
Letting contributors know what to expect can help them know when to (and not to) follow up on unanswered posts, as well as how to plan their own work.
Sharing perspectives on intent
While it's tempting to work towards a single shared definition of intent for an open source project, it's important to allow space for differing perspectives and emphases. I don't expect my understanding of a project to match perfectly with other collaborators and conversations around this helps my refine and stretch my understanding.
I am so grateful for Lauren McCarthy's ongoing mentorship and support, as well as the guidance I've received from Neha Batra and Billy Griffin. My discussions with each of you have deeply informed these thoughts.
Evelyn Masso is a person, developer, and writer. You can see her innermost thoughts on twitter and learn more about her work at outofambit.com.
This is the first piece in our Hacktoberfest open source series of tips by maintainers for maintainers. Stay tuned for a fresh post each Wednesday in October.
Hello there! If you've landed here, that probably means you're interested in building your first ml5.js project. If so, wonderful! We invite you to read on.
ml5.js is being developed to make machine learning more accessible to a wider audience. Along with supporting education and critical engagement with machine learning, the ml5 team is working actively to wrap exciting machine learning functionality in a friendlier and easier-to-use way. The following example introduces you ml5.js through a classic application of machine learning: image classification.
This example showcases how you can use a pre-trained model called MobileNet -- a machine learning model trained to recognize the content of certain images -- in ml5.js. The example aims to highlight a general pattern for how ml5.js projects are setup.
ml5.js is growing every day, so be sure to see some of the other applications of ml5 in the reference section and their accompanying examples for the latest offerings.
If you've arrived here, we assume you've checked out our quickstart page to get a simple ml5.js project set up. To get this to run, you'll need:
- 📝 A text editor (e.g. Atom, VSCode, Sublimetext)
- 💻 Your web browser: Chrome & Firefox preferred
- 🖼 An image to run your classification on
Your project directory should look something like this:
📂/hello-ml5: is the root project folder
- 📂/images: is a folder that contains your image
- 🖼 bird.png: is a .png image of a bird (it can also be something else!)
- 🗒index.html: is an .html file that has your html markup and library references
This example is built with p5.js. You can also find the same example without p5.js here.
P5 Js Library
Inside your sketch.js file you can type out (or copy and paste) the following code. Notice in this example we have a reference to 'images/bird.png'. You'll replace this with the name of your image.
Our sketch.js explained in 4 steps
Step 1: Define your variables
Here we define our variables that we will assign our classifier and image to.
Step 2: Load your imageClassifier and image
Use p5's preload() function to load our imageClassifier model and our bird image before running the rest of our code. Since machine learning models can be large, it can take time to load. We use preload() in this case to make sure our imageClassifier and image are ready to go before we can apply the image classification in the next step.
Step 3: Setup, classify, and display
Hello P5 Js
In p5.js we use the setup() function for everything in our program that just runs once. In our program, we use the setup() function to:
- create a canvas to render our image
- call .classify() on our classifier to classify our image
- render the image to the canvas
You will notice that the .classify() function takes two parameters: 1. the image you want to classify, and 2. a callback function called gotResult. Let's look at what gotResult does.
Step 4: Define the gotResult() callback function
The gotResult() function takes two parameters: 1. error, and 2. results. These get passed along to gotResult() when the .classify() function finishes classifying the image. If there is an error, then an error will be logged. If our classifier manages to recognize the content of the image, then a result will be returned.
In the case of our program, we create a div that displays the label and the confidence of the content of the image that has been classified. The nf() function is a p5 function that formats our number to a nicer string.
You've just made a simple machine learning powered program that:
- takes an image,
- classifies the content of that image, and
- displays the results all in your web browser!
Not all of our examples are structured exactly like this, but this provides a taste into how ml5.js is trying to make machine learning more approachable. Try using different images and seeing what kinds of things get returned.
Some guiding questions you might start to think about are:
- When classifying an image with MobileNet, does the computer see people? If not, why do you think that is?
- Do you notice that MobileNet is better at classifying some animals over others? Why do you think that is?