Hello! Welcome to the guidelines for writing p5.js documentation. This document is a remix of the following resources:
- Ruby on Rails API Documentation Guidlines (CC BY-SA 4.0)
- WordPress documentation guidelines for accessibility and inclusivity (CC0)
- Airbnb JavaScript Style Guide (MIT)
Our community is large and diverse. Many people learn to code using p5.js, and a large subset of those people are students in K–12 classes. After reading this guide, you will know:
- How to write effective, inclusive, and accessible prose for documentation purposes.
- How to write simple code samples for documentation purposes.
Table of Contents
Writing
Code
- Code Samples
- Comments
- Whitespace
- Semicolons
- Naming Conventions
- Variables
- Strings
- Boolean Operators
- Conditionals
- Iteration
- Objects
- Arrays
- Functions
- Arrow Functions
- Chaining
- Classes
- Assets
YUIDoc
We use YUIDoc to generate the p5.js API documentation. To generate the docs, navigate to the p5.js root directory, run npm install
, and execute:
$ npm run grunt yui:dev
The output will appear in docs/reference. Refer to the inline documentation guide for more information.
English
Please use American English (color, center, modularize, etc). See a list of American and British English spelling differences here.
Oxford Comma
Please use the Oxford comma (“red, white, and blue”, instead of “red, white and blue”).
Wording
Write simple, declarative sentences. Brevity is a plus: get to the point.
Write in the present tense: “Returns an object that…”, rather than “Returned an object that…” or “Will return an object that…“.
Start comments in upper case. Follow regular punctuation rules:
// Draws a fractal from a Julia set.
function drawFractal(c, radius, maxIter) {
// ...
}
Communicate the current way of doing things, both explicitly and implicitly. Use the idioms recommended in this guide. Reorder sections to emphasize favored approaches if needed. The documentation should be a model for best practices and approachable for beginners.
Documentation has to be brief but comprehensive. Explore and document edge cases. What happens for each combination of arguments? What bugs are most likely to appear in a beginner’s code?
Spell names correctly: p5.js, CSS, HTML, JavaScript, WebGL. When in doubt, refer to an authoritative source like their official documentation.
Unbiased Documentation
Write documentation without bias towards any kind of person. While documenting particularly demanding/sensitive topics, take the time to educate yourself. Ensure that your writing doesn’t hurt or offend someone unintentionally.
While writing unbiased documentation:
- Be inclusive of every gender identity and expression, sexual orientation, race, ethnicity, language, neuro-type, size, disability, class, religion, culture, subculture, political opinion, age, skill level, occupation, and background. Make examples as diverse as our community.
- Avoid politicized content. If political content is necessary, remain neutral.
- Follow accessibility guidelines.
- Avoid content that would insult or cause harm to people.
- Don’t make any generalizations about people, countries, and cultures. That includes positive or neutral generalizations.
- Don’t write prejudiced and discriminatory content against minority communities.
- Avoid terms related to historical events.
Prefer wordings that avoid “you”s and “your”s. For example, instead of:
If you need to declare a variable, it is recommended that you use `let`.
use this style:
Always use `let` to declare variables.
Pronouns
Recommended | Not Recommended |
---|---|
they | he or she |
them | him or her |
their | his or her |
theirs | his or hers |
themselves | himself or herself |
Accessibility and Disability
- Emphasize the reader rather than underlining their inconveniences.
- Don’t refer to a person with a disability as a disabled person. Use approved terminology for people with specific disabilities.
- Maintain a uniform structure throughout the p5.js documentation. Emphasize important points both stylistically and visually.
- Use a screen reader to test documentation. To test a screen reader, see List of screen readers.
- Consider multi-platform accessibility for all types of devices and operating systems.
- Create examples with all types of input devices such as voice and gesture based devices, controllers, mice, and keyboards.
- Don’t use ableist language. Be inclusive and unbiased while writing about accessibility and disability.
- Take a pragmatic approach to HTML semantics. Don’t add semantics purely for the sake of semantics. If there is an HTML structure that clearly matches the content, use that element. For example, a group of links should most likely use a list element.
- Use simple tables and tabular formats. Avoid span tags (such as rowspan and colspan). Tables prove to be difficult for screen readers.
Accessibility terminology
The following terminiology is adapted from the WordPress documentation guidelines for Writing inclusive documentation. For more background on people-first language, see the CDC’s guide on Communicating With and About People with Disabilities.
Recommended | Not Recommended |
---|---|
person with disability | the disabled, handicapped, differently abled, challenged, abnormal |
person without disability | normal person, healthy person, able-bodied |
has [disability] | victim of, suffering from, affected by, stricken with |
unable to speak, uses synthetic speech | dumb, mute |
deaf, low-hearing | hearing-impaired |
blind, low-vision | vision-impaired, visually-challenged |
cognitive or developmental disabilities | mentally-challenged, slow-learner |
person with limited mobility, person with a physical disability | crippled, handicapped |
Code Samples
Choose meaningful code samples that cover the basics as well as gotchas. Only use advanced syntax if it is necessary to explain how a feature works. Don’t draw five circles to explain something when one circle will convey the idea. The code samples themselves should follow the guidelines below.
Comments
- Use
//
for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block.
// Bad.
let magicWord = 'Please'; // Remember this.
// Good.
// Remember this.
let magicWord = 'Please';
// Bad.
if (keyIsPressed === true) {
thing1();
// This is an important note.
thing2();
}
// Good.
if (keyIsPressed === true) {
thing1();
// This is an important note.
thing2();
}
- Start all comments with a space to make it easier to read.
// Bad.
//Remember this.
let magicWord = 'Please';
// Good.
// Remember this.
let magicWord = 'Please';
- Use
//
for multiline comments.
// Bad.
/**
* I will use // for multiline comments.
* I will use // for multiline comments.
* I will use // for multiline comments.
* I will use // for multiline comments.
* I will use // for multiline comments.
*/
//Bad.
/*
I will use // for multiline comments.
I will use // for multiline comments.
I will use // for multiline comments.
I will use // for multiline comments.
I will use // for multiline comments.
*/
// Good.
// I will use // for multiline comments.
// I will use // for multiline comments.
// I will use // for multiline comments.
// I will use // for multiline comments.
// I will use // for multiline comments.
Whitespace
- Indent blocks 2 spaces.
// Bad.
function setup() {
∙∙∙∙createCanvas(400, 400);
}
// Bad.
function setup() {
∙createCanvas(400, 400);
}
// Good.
function setup() {
∙∙createCanvas(400, 400);
}
- Place 1 space before the leading brace.
// Bad.
function setup(){
createCanvas(400, 400);
}
// Good.
function setup() {
createCanvas(400, 400);
}
- Place 1 space before the opening parenthesis in control statements such as
if
andfor
. Place no space between the argument list and the function name.
// Bad.
if(keyIsPressed === true) {
doStuff ();
}
// Good.
if (keyIsPressed === true) {
doStuff();
}
// Bad.
function setup () {
createCanvas (400, 400);
}
// Good.
function setup() {
createCanvas(400, 400);
}
- Place spaces between operators.
// Bad.
let y=x+5;
// Good.
let y = x + 5;
Semicolons
- Yep.
Why? JavaScript’s automatic semicolon insertion can lead to subtle bugs.
// Bad.
let x = 0
// Good.
let x = 0;
Naming Conventions
- Avoid single letter names. Be descriptive.
// Bad.
function f(x, y) {
// ...
}
// Good.
function vectorField(x, y) {
// ...
}
- Name objects, functions, and instances using camelCase.
// Bad.
let OBJEcttsssss = {};
// Bad.
let this_is_my_object = {};
// Good.
let thisIsMyObject = {};
- Name classes using PascalCase.
// Bad.
class player {
constructor(name) {
this.name = name;
}
}
// Good.
class Player {
constructor(name) {
this.name = name;
}
}
- Don’t use trailing or leading underscores.
Why? JavaScript doesn’t have private properties or methods.
// Bad.
class Spy {
constructor(secret) {
this._secret = secret;
}
}
// Good.
class Spy {
constructor(secret) {
this.secret = secret;
}
}
Variables
- Avoid using
var
to declare variables.
Why? Variables declared with
var
have confusing scoping rules. These lead to subtle bugs.
// Bad, because it looks reasonable.
circle(x, y, 50);
var x = 200;
var y = 200;
// Good, because it throws a ReferenceError.
circle(x, y, 50);
let x = 200;
let y = 200;
- Always use
let
to declare variables. Avoid usingconst
.
Why? Variables declared with
let
are easier to reason about than those declared withvar
. Variables are often reassigned in sketches, so it’s helpful to default tolet
.
// Bad.
flower = '🌸';
var flower = '🌸';
const flower = '🌸';
// Good.
let flower = '🌸';
- Use one
let
declaration per variable or assignment.
Why? It’s easier to read and to add new variable declarations.
// Bad.
let positions = getPositions(),
startSearch = true,
dragonball = 'z';
// Good.
let positions = getPositions();
let startSearch = true;
let dragonball = 'z';
- Assign variables where needed and place them in a reasonable place.
Why?
let
is block scoped and not function scoped.
// Bad - unnecessary search.
function getCharacter(name = 'default') {
let character = characters.find((c) => c.name === name);
if (name === 'default') {
return false;
}
if (character) {
return character;
}
return false;
}
// Good.
function getCharacter(name = 'default') {
if (name === 'default') {
return false;
}
let character = characters.find((c) => c.name === name);
if (character) {
return character;
}
return false;
}
- Avoid using unary increments and decrements (
++
,--
).
Why? Unary increment and decrement statements are subject to automatic semicolon insertion. This can cause silent errors with incrementing or decrementing values. It’s also more expressive to update variables with statements like num
+= 1
instead ofnum++
.
// Bad.
let num = 1;
num++;
--num;
// Good.
let num = 1;
num += 1;
num -= 1;
Strings
- Use single quotes
''
for strings.
// Bad.
let name = "Hilma af Klint";
// Bad - template literals should contain interpolation or newlines.
let name = `Hilma af Klint`;
// Good.
let name = 'Hilma af Klint';
- Don’t concatenate strings that cause the line to go over 80 characters.
Why? Broken strings are hard to read and make code less searchable.
// Bad.
let essay = 'You see us as you want to see us: \
in the simplest terms, in the most convenient definitions.';
// Bad.
let essay = 'You see us as you want to see us: ' +
'in the simplest terms, in the most convenient definitions.';
// Good.
let essay = 'You see us as you want to see us: in the simplest terms, in the most convenient definitions.';
- Use template strings instead of concatenation when needed.
Why? Template strings have a concise syntax. They also provide proper newlines and string interpolation features.
let name = 'Dave';
// Bad.
text(name + ', this conversation can serve no purpose anymore. Goodbye.' + name, 0, 0);
// Good.
text(`${name}, this conversation can serve no purpose anymore. Goodbye.`, 0, 0);
- Do not unnecessarily escape characters in strings.
Why? Backslashes harm readability.
// Bad.
let bad = '\'this\' \i\s \"quoted\"';
// Good.
let good = 'Air quotes make you look "cool".';
Boolean Operators
Use
===
and!==
over==
and!=
.Don’t use shortcuts for booleans.
Why? It’s easier to understand for beginners.
// Bad.
if (mouseIsPressed) {
// ...
}
// Good.
if (mouseIsPressed === true) {
// ...
}
// Bad.
if (name) {
// ...
}
// Good.
if (name !== '') {
// ...
}
// Bad.
if (collection.length) {
// ...
}
// Good.
if (collection.length > 0) {
// ...
}
Don’t use
switch
statements unless it’s necessary.Use parentheses when mixing operators. The only exceptions are the arithmetic operators
+
,-
, and**
.
Why? It’s easier to read and avoids subtle bugs.
// Bad.
let huh = a && b < 0 || c > 0 || d + 1 === 0;
// Good.
let huh = (a && b < 0) || c > 0 || (d + 1 === 0);
// Bad.
if (a || b && c) {
return d;
}
// Good.
if (a || (b && c)) {
return d;
}
// Bad.
let what = a + b / c * d;
// Good.
let what = a + (b / c) * d;
Conditionals
- Use braces with all multiline blocks.
// Bad.
if (mouseIsPressed === true)
circle(mouseX, mouseY, 50);
// Better.
if (mouseIsPressed === true) circle(mouseX, mouseY, 50);
// Best.
if (mouseIsPressed === true) {
circle(mouseX, mouseY, 50);
}
- Put
else
on the same line as the precedingif
block’s closing brace.
// Bad.
if (mouseIsPressed === true) {
thing1();
thing2();
}
else {
thing3();
}
// Good.
if (mouseIsPressed === true) {
thing1();
thing2();
} else {
thing3();
}
- Don’t use an
else
block after anif
block that always executes areturn
statement.
// Bad.
function mouseIsOnLeft() {
if (mouseX < width * 0.5) {
return true;
} else {
return false;
}
}
// Good.
function mouseIsOnLeft() {
if (mouseX < width * 0.5) {
return true;
}
return false;
}
- If a condition gets too long, place each (grouped) condition on a new line. The logical operator should begin the line.
Why? It’s easier to read.
// Bad.
if ((number === 123 || letters === 'abc') && mouseIsPressed === true && keyIsPressed === true) {
doStuff();
}
// Good.
if (
(number === 123 || letters === 'abc')
&& mouseIsPressed === true
&& keyIsPressed === true
) {
doStuff();
}
Don’t use selection operators in place of conditionals.
// Bad. refrigeratorIsRunning && goCatchIt(); // Good. if (refrigeratorIsRunning === true) { goCatchIt(); }
Iteration
- Don’t use a
while
ordo-while
loops unless it’s necessary. Usefor
loops to iterate a fixed number of times.
let numPetals = 7;
// Bad.
let i = 0;
while (i < numPetals) {
ellipse(0, 0, 20, 80);
rotate(PI / numPetals);
i += 1;
}
// Good.
for (let i = 0; i < numPetals; i += 1) {
ellipse(0, 0, 20, 80);
rotate(PI / numPetals);
}
- Don’t use
for
loops to iterate over arrays.
Why? Pure functions are easier to reason about than side effects.
Use
forEach()
/map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/...
to iterate over arrays. UseObject.keys()
/Object.values()
/Object.entries()
to produce arrays for iterating over objects.
let diameters = [50, 40, 30, 20, 10];
// Bad.
for (let i = 0; i < diameters.length; i += 1) {
circle(0, 0, diameters[i]);
}
// Bad.
for (let d of diameters) {
circle(0, 0, d);
}
// Good.
diameters.forEach((d) => circle(0, 0, d));
Objects
- Use the literal syntax for object creation.
// Bad.
let ball = new Object();
// Good.
let ball = {};
- Only quote properties that are invalid identifiers.
Why? It’s easier to read and improves syntax highlighting. JavaScript engines also have an easier time optimizing for performance.
// Bad.
let secretObject = {
'x': 100,
'y': 200,
'top-secret': 'classified',
};
// Good.
let secretObject = {
x: 3,
y: 4,
'top-secret': 'classified',
};
- Use dot notation to access properties.
let turtle = {
name: 'Leonardo',
color: 'dodgerblue',
weapon: '🗡️',
food: '🍕',
};
// Bad.
let turtleName = turtle['name'];
// Good.
let turtleName = turtle.name;
- Use bracket notation
[]
to access properties with a variable.
let turtle = {
name: 'Leonardo',
color: 'dodgerblue',
weapon: '🗡️',
food: '🍕',
};
function getProp(prop) {
return turtle[prop];
}
let turtleName = getProp('name');
- Don’t use leading commas.
// Bad.
let mathematician = {
firstName: 'Ada'
, lastName: 'Lovelace'
};
// Good.
let mathematician = {
firstName: 'Ada',
lastName: 'Lovelace',
};
- Add a trailing comma.
// Bad.
let artist = {
firstName: 'Lauren',
lastName: 'McCarthy'
};
// Good.
let artist = {
firstName: 'Lauren',
lastName: 'McCarthy',
};
Arrays
- Use the literal syntax for array creation.
// Bad.
let images = new Array();
// Good.
let images = [];
- Use Array#push instead of direct assignment to add items to an array.
let lyrics = [];
// Bad.
lyrics[lyrics.length] = 'Little rough around the edges, but I keep it smooth';
// Good.
lyrics.push('Little rough around the edges, but I keep it smooth');
- Use the
slice()
method to copy arrays.
// Bad.
let numbersCopy = [];
for (let i = 0; i < numbers.length; i += 1) {
numbersCopy[i] = numbers[i];
}
// Good.
let numbersCopy = numbers.slice();
- Write arrays on multiple lines when it improves readibility. Use line breaks after the opening bracket and before the closing bracket. Add a trailing comma.
// Bad.
let matrix = [[1, 0, 0],
[0, 1, 0],
[0, 0, 1]];
// Good.
let matrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1],
];
// Also good.
let matrix = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
Functions
- Use function declarations instead of named function expressions.
Why? Function declarations have some gotchas, but they are easier to understand for beginners.
// Bad.
let foo = function () {
// ...
};
// Bad.
let foo = () => {
// ...
};
// Good.
function foo() {
// ...
}
- Use default parameter syntax. Don’t mutate function arguments.
// Bad.
function createBall(diameter) {
diameter = diameter || 50;
// ...
}
// Good.
function createBall(diameter = 50) {
// ...
}
- Always put default parameters last.
// Bad.
function drawSpiral(angle = 90, length) {
// ...
}
// Good.
function drawSpiral(length, angle = 90) {
// ...
}
Arrow Functions
- Use arrow function notation for anonymous functions. Callbacks are a common case for this syntax.
Why? The syntax is more concise. It also creates a version of the function that executes in the context of
this
, which is often helpful.
Why not? If the anonymous function is complex, rewrite it as a declared function.
// Bad.
function setup() {
loadImage('assets/moonwalk.jpg', function (img) {
image(img, 0, 0);
});
}
// Good.
function setup() {
loadImage('assets/moonwalk.jpg', (img) => {
image(img, 0, 0);
});
}
// Bad.
function preload() {
loadImage('assets/moonwalk.jpg', (img) => {
// Complex preprocessing...
});
}
// Good.
function preload() {
loadImage('assets/moonwalk.jpg', processImage);
}
function processImage(img) {
// Complex preprocessing...
}
- Use the implicit return when possible. Omit braces if the function body returns a single statement without side effects. Otherwise, keep the braces and use a
return
statement.
Why? It’s easier to read.
// Bad.
[1, 2, 3].map((number) => {
let squared = number ** 2;
`${number} squared is ${squared}.`;
});
// Bad.
[1, 2, 3].map((number) => {
let squared = number ** 2;
return `${number} squared is ${squared}.`;
});
// Good.
[1, 2, 3].map((number) => `${number} squared is ${number ** 2}.`);
- Always include parentheses around arguments.
Why? Doing so reduces bugs when changing parameters.
// Bad.
[1, 2, 3].map(number => number * number);
// Good.
[1, 2, 3].map((number) => number * number);
Chaining
- Use individual function calls instead of function chaining.
Why? To accommodate users who may not be familiar with the concept of function chaining.
// Bad.
fill(0)
.strokeWeight(6)
.textSize(20);
// Bad.
fill(0).strokeWeight(6).textSize(20);
// Good.
fill(0);
strokeWeight(6);
textSize(20);
Classes
- Always use
class
. Avoid manipulatingprototype
directly. The only exception is explaining how to create libraries.
Why?
class
syntax is more concise and easier to reason about.
// Bad.
function Mover(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
Mover.prototype.update = function () {
this.x += 1;
this.y += 1;
};
Mover.prototype.render = function () {
circle(this.x, this.y, 2 * this.radius);
};
// Good.
class Mover {
constructor(x, y, radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
update() {
this.x += 1;
this.y += 1;
}
render() {
circle(this.x, this.y, 2 * this.radius);
}
}
- Use
extends
for inheritance.
class RandomMover extends Mover {
update() {
this.x += random(-1, 1);
this.y += random(-1, 1);
}
}
- Make sure that custom
toString()
methods don’t cause side effects.
// Bad.
class Mover {
// ...
toString() {
this.x += 1;
return `Mover at (${this.x}, ${this.y})`;
}
}
// Good.
class Mover {
// ...
toString() {
return `Mover at (${this.x}, ${this.y})`;
}
}
- Don’t write an empty constructor or one that only delegates to a parent class.
Why? Classes have a default constructor if one isn’t specified.
// Bad.
class Dot {
constructor() {}
render() {
circle(mouseX, mouseY, 50);
}
}
// Good.
class Dot {
render() {
circle(mouseX, mouseY, 50);
}
}
// Bad.
class DragonBall extends Ball {
constructor(x, y, d) {
super(x, y, d);
}
}
// Good.
class DragonBall extends Ball {
constructor(x, y, d, numStars) {
super(x, y, d);
this.numStars = numStars;
}
}
- Avoid duplicate class members.
Why? Duplicate class member declarations prefer the last one. Having duplicates often means there’s a bug.
// Bad.
class Mover {
// ...
update() {
this.x += this.xspeed;
this.y += this.yspeed;
}
update() {
this.x = 0;
this.y = 0;
}
}
// Good.
class Mover {
// ...
update() {
this.x += this.xspeed;
this.y += this.yspeed;
}
reset() {
this.x = 0;
this.y = 0;
}
}
Assets
- Always load assets from a folder called “assets”.
Why? It models good project organization. It’s also required for assets to load on the p5.js website. Place assets in the following folders to include them in our online documentation:
- Examples: src/data/examples/assets
- Reference Pages: src/templates/pages/reference/assets
- Learn Pages: src/assets/learn
let img;
// Bad.
function preload() {
img = loadImage('moonwalk.jpg');
}
// Good.
function preload() {
img = loadImage('assets/moonwalk.jpg');
}