p5.brush.js is a versatile library for the p5.js ecosystem, tailored for artists, designers, and hobbyists who wish to explore natural textures in generative art. This library extends the drawing capabilities of p5.js by introducing a rich set of tools that allow for the creation of dynamic and customizable brushes, vector-fields, and fill modes.
With p5.brush.js, you can easily configure and manage intricate drawing systems, inject life into your sketches with organic movements, and apply complex vector fields to control the flow and form of strokes. The library is designed with texture quality in mind, and may only be suitable for high-resolution artworks, not real-time interactive pieces.
Whether you're looking to simulate natural media, create patterned backgrounds, or design intricate particle systems, p5.brush.js offers the functionalities to turn your vision into reality. The API is straightforward and modular, providing both high-level functions for quick setup and in-depth customization options for advanced users.
Embrace the full potential of your creative coding projects with p5.brush.js, where every stroke is a brush with possibility.
Visit the library website here! (more examples soon)
Important note: p5.brush requires p5.js 1.11 or higher.
To set up your project, add p5.min.js
p5.brush.js
to your HTML file. You can download the last version of the p5.brush.js library in the dist folder.
Place the script tags in the following order:
<!-- Commented version of p5.brush.js, with a Spectral.js dependency -->
<script src="path_to/p5.min.js"></script>
<script src="path_to/p5.brush.js"></script>
Replace path_to with the actual path to the script in your project directory or the URL if you are using a CDN.
Alternatively, you can link to a p5.brush.js
file hosted online. All versions are stored in a CDN (Content Delivery Network). You can find a history of these versions in the p5.js CDN. In this case you can change the link to:
<!-- Online version of p5.brush -->
<script src="https://cdn.jsdelivr.net/npm/p5.brush"></script>
Install the npm package. p5.brush requires p5.js as a peer dependency.
npm install p5.brush --save
After that, import p5.brush functions to your sketch:
import * as brush from 'p5.brush'
If you are using p5 and p5.brush as modules, you will need to use instance mode. Read below.
By default, all p5.js functions are in the global namespace (i.e. bound to the window object), meaning you can call them simply ellipse(), fill(), etc. However, this might be inconvenient if you are mixing with other JS libraries (synchronously or asynchronously) or writing long programs of your own. p5.js currently supports a way around this problem called "instance mode". In instance mode, all p5 functions are bound up in a single variable instead of polluting your global namespace.
If you plan to use p5 instance mode, you need to load p5.brush in a specific way:
-
Use
brush.instance()
before the setup and draw functions, pointing to your sketch id and the p5 function argumentExample:
let sketch = function(p) { let x = 100; let y = 100; // Register instance method here, sending your function arg p brush.instance(p) p.setup = function() { // Important to create the canvas in WEBGL mode p.createCanvas(700, 410, p.WEBGL); // Don't forget to load the library after canvas is created brush.load() }; p.draw = function() { p.background(0); brush.fill("red", 75); brush.rect(x, y, 50, 50); }; }; let myp5 = new p5(sketch);
p5.brush.js enhances the p5.js framework with a set of tools that allow for sophisticated drawing and rendering techniques.
- Custom Configuration: Customize your drawing strokes with the ability to select different buffers and leverage a custom random number generator to introduce variability in procedural designs.
- Vector Field Integration: Direct the motion of your brush strokes with vector fields, crafting fluid, dynamic visuals within your sketches.
- Dynamic Brush System: Select from an array of brushes, each offering distinct characteristics, to create a variety of effects and textures.
- Brush and Field Management: Manage and switch between brushes and vector fields with ease, adapting to the needs of your project seamlessly.
- Extensibility: Expand the library's capabilities by integrating your own custom brushes and vector fields, tailoring the toolset to your artistic vision.
- Custom Brush Tips: Load and use your own custom brush tip assets.
- Interactive Brush Tips: Utilize pressure-sensitive brush tips for interactive drawing, adding a level of responsiveness to your canvas work.
- Hatch Patterns: Implement hatching techniques with precision control over the patterns' density and orientation, enhancing your artwork with automated detailing.
- Intuitive Spline and Curve Generation: Generate smooth and accurate curves and splines effortlessly, simplifying the process of intricate path creation.
- Watercolor Fill System: Achieve the subtle nuances of watercolor with a digital fill system designed to blend and diffuse colors in a naturally fluid way.
With p5.brush.js, your digital canvas becomes a playground for innovation and expression, where each tool is fine-tuned to complement your unique creative process.
.
p5.brush.js provides a comprehensive API for creating complex drawings and effects. Below are the categorized functions and classes available in the library.
Section | Functions | Section | Functions | |
---|---|---|---|---|
Utility | brush.push() | Hatch Operations | brush.hatch() | |
brush.pop() | brush.noHatch() | |||
brush.rotate() | brush.setHatch() | |||
brush.scale() | Geometry | brush.line() | ||
brush.reDraw() | brush.flowLine() | |||
brush.reBlend() | brush.beginStroke() | |||
Vector-Fields | brush.field() | brush.segment() | ||
brush.noField() | brush.endStroke() | |||
brush.refreshField() | brush.spline() | |||
brush.listFields() | brush.plot() | |||
brush.addField() | brush.rect() | |||
Brush Management | brush.box() | brush.circle() | ||
brush.add() | brush.beginShape() | |||
brush.clip() | brush.vertex() | |||
brush.noClip() | brush.endShape() | |||
Stroke Operations | brush.set() | brush.polygon() | ||
brush.pick() | Configuration | brush.seed() | ||
brush.stroke() | brush.load() | |||
brush.noStroke() | brush.preload() | |||
brush.strokeWeight() | brush.colorCache() | |||
Fill Operations | brush.fill() | brush.scaleBrushes() | ||
brush.noFill() | brush.remove() | |||
brush.bleed() | brush.instance() | |||
brush.fillTexture() | Classes | brush.Polygon() | ||
brush.Plot() | ||||
brush.Position() |
-
brush.push()
- Description: The push() function saves the current brush, hatch, and fill settings and transformations, while pop() restores these settings. Note that these functions are always used together.
-
brush.pop()
- Description: The push() function saves the current brush, hatch, and fill settings and transformations, while pop() restores these settings. Note that these functions are always used together.
brush.rotate(angle)
- Description: Rotates following shapes by the amount specified by the angle parameter. This function accounts for angleMode(), so angles can be entered in either RADIANS or DEGREES. Objects are always rotated around their relative position to the origin and positive numbers rotate objects in an anti-clockwise direction. Transformations apply to everything that happens after and subsequent calls to the function accumulate the effect. This function can be further controlled by brush.push() and brush.pop().
brush.scale(scale)
- Description: Increases or decreases the size of shapes and strokes by expanding or contracting vertices. Objects always scale from their relative origin to the coordinate system. Scale values are specified as decimal percentages. For example, the function call scale(2.0) increases the dimension of a shape by 200%. Transformations apply to everything that happens after and subsequent calls to the function multiply the effect. For example, calling scale(2.0) and then scale(1.5) is the same as scale(3.0).
-
brush.reDraw()
- Description: p5.brush uses several buffers and caches to make the drawing operations more performant. Use the reDraw() function if you want to force noBlend brushes to be drawn into the canvas. This function is designed to help maintain the correct draw order for the different strokes and shapes.
-
brush.reBlend()
- Description: p5.brush uses several buffers and caches to make the drawing operations more performant. Use the reDraw() function if you want to force Blend brushes to be drawn into the canvas. This function is designed to help maintain the correct draw order for the different strokes and shapes.
Vector Fields allow for dynamic control over brush stroke behavior, enabling the creation of complex and fluid motion within sketches.
brush.field(name)
- Description: Activates a named vector field. When a vector field is active, it influences the flow and direction of the brush strokes for shapes drawn thereafter. It is important to note that certain shapes may be exempt from this influence; such exceptions will be clearly documented in the API for each specific geometry.
- Parameters:
name
(String): The identifier for the vector field to be activated. This can be a name of one of the predefined fields or a custom field created withbrush.addField()
.
- Default Fields: The library comes with a set of built-in vector fields:
curved
,truncated
,zigzag
,seabed
, andwaves
. These, as well as any custom fields added, can be activated using this function. - Usage:
Once a vector field is activated, it affects how the subsequent shapes are drawn, aligning them with its directional flow, unless stated otherwise in the documentation
// To activate the "waves" vector field brush.field("waves"); // To activate a custom vector field named "myCustomField" brush.field("myCustomField");
brush.noField()
- Description: Deactivates the currently active vector field, returning the drawing behavior to its default state where shapes are not influenced by any vector field. Any shapes drawn after this function call will not be affected by the previously active vector field.
- Usage:
Use this function when you want to draw shapes that are unaffected by the directional flow of any vector field, effectively resetting the drawing behavior to its original state.
// Deactivate the current vector field brush.noField();
brush.refreshField(time)
- Description: Updates the current vector field values using its time-dependent generator function. Ideal for animations that require the vector field to change over time, influencing the movement of strokes and shapes in a natural way.
- Parameters:
time
(Number): The time input for the vector field generator function, typically related to the frame count.
- Usage:
This function will invoke the generator function of the active vector field with the provided time argument, allowing the field to evolve and create fluid, dynamic animations in the rendering.
// In the draw loop, refresh the vector field based on the frame count function draw() { brush.refreshField(frameCount / 10); // Additional drawing code }
brush.listFields()
- Description: Retrieves an iterator containing the names of all the available vector fields within the system. This includes both the default fields provided by the library and any custom fields that have been added using
brush.addField()
. - Returns:
Iterator<string>
- An iterator that yields the names of the vector fields. - Usage:
Use
// Get an iterator of all vector field names let fieldNames = brush.listFields(); // Loop through the names using the iterator for (let name of fieldNames) { console.log(name); }
brush.listFields()
to access the names of all existing vector fields, which can then be used to activate or modify fields as needed.
- Description: Retrieves an iterator containing the names of all the available vector fields within the system. This includes both the default fields provided by the library and any custom fields that have been added using
brush.addField(name, generatorFunction)
- Description: Adds a custom vector field to the list of available fields. This advanced function requires a unique name for the field and a generator function that defines the behavior of the vector field over time.
- Parameters:
name
(String): A unique identifier for the vector field.generatorFunction
(Function): A function that generates the field values. It takes a time parametert
, loops through the vector field cells, assigns angular values based on custom logic, and returns the modifiedfield
array.
- Default Fields: The library includes several pre-defined vector fields. Users can add their own to extend the functionality.
- Usage: To add a vector field that creates wave-like motions:
brush.addField("waves", function(t, field) { let sinrange = random(10,15) + 5 * sin(t); let cosrange = random(3,6) + 3 * cos(t); let baseAngle = random(20,35); for (let column = 0; column < field.length; column++) { for (let row = 0; row < field[0].length; row++) { let angle = sin(sinrange * column) * (baseAngle * cos(row * cosrange)) + random(-3,3); field[column][row] = angle; } } return field; });
- Note: It's important that your loops create a grid of
field.length
xfield[0].length
. It's necessary to fill all thefield
cells with a numeric value. Return this array when you've filled the values. The angles MUST BE in Degrees.
brush.addField("name_field", function(t, field) { let field = FF.genField() // Related functions for angle calculation for (let i = 0; i < field.length; i++) { for (let j = 0; j < field[0].length; j++) { // Related functions for angle calculation here field[i][j] = CalculatedAngle; } } return field; });
- Note: It's important that your loops create a grid of
Functions for managing brush behaviors and properties.
brush.box()
- Description: Retrieves an array containing the unique names of all available brushes. This function is useful for accessing the variety of brushes included in the library, which range from different pencil types to markers and specialized brushes like the hatch brush. Of course, the function will also return the custom brushes you've created.
- Returns:
Array<string>
- An array listing the names of all brushes. - Default Brushes: The library includes a default set of 11 brushes:
2B
,HB
,2H
,cpencil
,pen
,rotring
,spray
,marker
,marker2
,charcoal
, andhatch_brush
(for clean hatching). - Usage:
// Retrieve a list of all available brush names let brushes = brush.box(); console.log(brushes); // Logs the array of brush names
brush.box()
allows you to explore and select from the various brushes, facilitating the choice of the appropriate brush for different artistic needs.
brush.add(name, params)
- Description: Adds a new brush to the brush list with specified parameters, defining the brush's behavior and appearance. This function allows for extensive customization, enabling the creation of unique brush types suited to various artistic needs.
- Parameters:
name
(String): A unique identifier for the brush.params
(BrushParameters): An object containing the parameters for the brush. The parameters include:type
: (standard
|spray
|marker
|custom
|image
) The tip type.weight
: Base size of the brush tip, in canvas units.vibration
: Vibration of the lines, affecting spread, in canvas units.definition
: (Number from 0-1) Between 0 and 1, defining clarity. Unnecessary for custom, marker, and image type brushes.quality
: Higher values lead to a more continuous line. Unnecessary for custom, marker, and image type brushes.opacity
: (Number from 0-255) Base opacity of the brush (affected by pressure).spacing
: Spacing between points in the brush stroke, in canvas units.blend
: (Boolean) Enables or disables realistic color mixing (default true for marker, custom, and image brushes).pressure
: An object or function defining the pressure sensitivity.type
: 'standard" or 'custom". Use standard for simple gauss bell curves. Use 'custom' for custom pressure curves.min_max
: (Array [min, max]) Define min and max pressure (reverse for inverted presure).curve
: function or array.- Standard pressure: [a, b] - If 'standard' pressure curve, pick a and b values for the gauss curve. a is max horizontal mvt of the bell, b changes the slope.
- Custom pressure: (x) => function - If 'custom' pressure curve, define the curve function with a curve equation receiving values from 0 to 1, returning values from 0 to 1. Use https://mycurvefit.com/
tip
: (For custom types) A function defining the geometry of the brush tip. Remove if unnecessary.image
: (For image types) The url path to your image, which MUST be in the same baseURL. Remove if unnecessary.rotate
: (none
|natural
|random
) Defines the tip angle rotation.
- Usage:
By using
// You create an image brush like this: brush.add("watercolor", { type: "image", weight: 10, vibration: 2, opacity: 30, spacing: 1.5, blend: true, pressure: { type: "custom", min_max: [0.5,1.2], // This formula implies that the pressure changes in a linear distribution through the whole length of the line. // Minimum pressure at the start, maximum pressure at the end. curve: (x) => 1-x }, image: { src: "./brush_tips/brush.jpg", }, rotate: "random", }) // You create a custom tip brush like this: brush.add("watercolor", { type: "custom", weight: 5, vibration: 0.08, opacity: 23, spacing: 0.6, blend: true, pressure: { type: "standard", min_max: [1.35,1], curve: [0.35,0.25] // Values for the bell curve }, tip: (_m) => { // in this example, the tip is composed of two squares, rotated 45 degrees // Always execute drawing functions within the _m buffer! _m.rotate(45), _m.rect(-1.5,-1.5,3,3), _m.rect(1,1,1,1); }, rotate: "natural", })
brush.add()
, you can expand your brush collection with custom brushes tailored to specific artistic effects and styles.
brush.clip(clippingRegion)
- Description: Sets a rectangular clipping region for all subsequent brush strokes. When this clipping region is active, brush strokes outside this area will not be rendered. This is particularly useful for ensuring that strokes, such as lines and curves, are contained within a specified area. The clipping affects only stroke and hatch operations, not fill operations. The clipping remains in effect for all strokes drawn after the call to
brush.clip()
untilbrush.noClip()
is used. - Parameters:
clippingRegion
(Array): An array defining the clipping region as[x1, y1, x2, y2]
, with(x1, y1)
and(x2, y2)
being the corners of the clipping rectangle.
- Usage:
// Set a clipping region brush.clip([10, 10, 250, 200]); // Draw a line - it will be clipped according to the region brush.line(100, 90, 300, 40); // Remove the clipping region brush.noClip(); // Draw another line - it will not be clipped brush.line(0, 0, 200, 300);
- Description: Sets a rectangular clipping region for all subsequent brush strokes. When this clipping region is active, brush strokes outside this area will not be rendered. This is particularly useful for ensuring that strokes, such as lines and curves, are contained within a specified area. The clipping affects only stroke and hatch operations, not fill operations. The clipping remains in effect for all strokes drawn after the call to
brush.noClip()
- Description: Disables the current clipping region, allowing subsequent brush strokes to be drawn across the entire canvas without being clipped. Use this function to revert to the default state where strokes are unrestricted.
- Usage:
// Disable the clipping region brush.noClip();
Stroke Operations encompass methods for manipulating and applying brushes to strokes (aka lines), providing artists with precise control over their brushwork.
brush.set(brushName, color, weight)
- Description: Selects and sets up the current brush with a specific name, color, and weight. This function is crucial for preparing the brush to draw strokes with the desired characteristics.
- Parameters:
brushName
(String): The name of the brush to be used.color
(String|p5.Color): The color for the brush, which can be specified as a HEX string or a p5.Color object.weight
(Number): The weight or size of the brush.
- Note: This function will automatically activate stroke mode for subsequent geometries.
- Usage:
By using
// Set the "HB" brush with a specific blue color and weight factor 1 brush.set("HB", "#002185", 1);
brush.set()
, you can quickly switch between different brushes, colors, and sizes, allowing for dynamic and varied stroke applications in your artwork.
brush.pick(brushName)
- Description: Selects the current brush type based on the specified name. This function is used to change the brush type without altering its color or weight.
- Parameters:
brushName
(String): The name of the brush to set as current.
- Usage:
Use// Set the current brush to "charcoal" brush.pick("charcoal");
brush.pick()
to switch between different brush types while maintaining the current color and weight settings.
brush.stroke(r, g, b)
orbrush.stroke(color)
- Description: Sets the color of the current brush. This function can take either RGB color components or a CSS color string/p5.Color object. It also activates stroke mode for subsequent shapes.
- Parameters:
r
(Number|String|p5.Color): The red component of the color, a CSS color string, or a p5.Color object.g
(Number): Optional. The green component of the color.b
(Number): Optional. The blue component of the color.
- Usage:
Use
// Set the brush color using RGB values brush.stroke(105, 111, 34); // Or set the brush color using a HEX string brush.stroke("#002185");
brush.stroke()
to define the color of your brush strokes, enabling a diverse palette for your artwork.
brush.noStroke()
- Description: Disables the stroke for subsequent drawing operations. This function is useful when you want to draw shapes without an outline.
- Usage:
// Disable stroke for the upcoming shapes brush.noStroke();
brush.noStroke()
is essential for creating drawings where only fill and no outline is desired.
brush.strokeWeight(weight)
- Description: Sets the weight or size of the current brush. The specified weight acts as a multiplier to the base size of the brush, allowing for dynamic adjustments.
- Parameters:
weight
(Number): The weight to set for the brush.
- Returns: None.
- Usage:
// Set the brush stroke weight to 2.3 times the base size brush.strokeWeight(2.3);
brush.strokeWeight()
provides the flexibility to easily adjust the thickness of your brush strokes, enhancing the expressiveness of your drawing tools.
The Fill Management section focuses on managing fill properties for shapes, enabling complex fill operations with effects like bleeding to simulate watercolor-like textures. These methods set fill colors with opacity, control bleed intensity, and manage fill operations. The watercolor fill effect is inspired by Tyler Hobbs' generative art techniques.
** IMPORTANT: ** At the moment, fill operations expect an array of vertices in the clockwise direction. Otherwise, the fill will "bleed" to the inside, destroying the effect. I'll try to fix this on a forthcoming update.
brush.fill(a, b, c, d)
orbrush.fill(color, opacity)
- Description: Sets the fill color and opacity for subsequent shapes, activating fill mode. This function can accept either RGB color components with opacity or a CSS color string/p5.Color object with an optional opacity.
- Parameters:
a
(Number|String|p5.Color): The red component of the color or grayscale value, a CSS color string, or a p5.Color object.b
(Number): Optional. The green component of the color or grayscale opacity if two arguments are used.c
(Number): Optional. The blue component of the color.d
(Number): Optional. The opacity of the color.
- Usage:
// Set the fill color using RGB values and opacity brush.fill(244, 15, 24, 75); // Or set the fill color using a HEX string and opacity brush.fill("#002185", 110);
brush.fill()
allows for detailed control over the color and transparency of the fill.
brush.noFill()
- Description: Disables the fill for subsequent drawing operations. Useful for creating shapes or lines without a fill.
- Usage:
// Disable fill for the upcoming shapes brush.noFill();
brush.bleed(strength, direction)
- Description: Adjusts the bleed and texture levels for the fill operation, mimicking the behavior of watercolor paints. This function adds a natural and organic feel to digital artwork.
- Parameters:
strength
(Number): The intensity of the bleed effect, capped at 0.5.direction
(String): Optional. "out" or "in". Defines the direction of the bleed effect_borderIntensity
(Number): The intensity of the border watercolor effect, ranging from 0 to 1.
- Usage:
// Set the bleed intensity and direction for a watercolor effect brush.bleed(0.3, "out");
brush.fillTexture(textureStrength, borderIntensity)
- Description: Adjusts the texture levels for the fill operation, mimicking the behavior of watercolor paints. This function adds a natural and organic feel to digital artwork.
- Parameters:
textureStrength
(Number): The texture of the fill effect, ranging from 0 to 1.borderIntensity
(Number): The intensity of the border watercolor effect, ranging from 0 to 1.
- Usage:
// Set the fill texture and border intensity brush.fillTexture(0.6, 0.4);
brush.fillAnimatedMode(mode)
- Description: Toggles certain operations on or off to ensure a consistent bleed effect for animations, especially useful at varying bleed levels.
- Parameters:
mode
(Boolean): Set totrue
to enable animated mode,false
to disable.
- Usage:
// Enable animated mode for consistent bleed effects in animations brush.fillAnimatedMode(true);
brush.fillAnimatedMode()
is valuable for animators and artists working on dynamic projects, where maintaining consistent fill effects across frames is crucial.
The Hatching section focuses on creating and drawing hatching patterns, which involves drawing closely spaced parallel lines. These functions offer control over the hatching style and application.
brush.hatch(dist, angle, options)
- Description: Activates hatching with specified parameters for subsequent geometries. This function enables the drawing of hatching patterns with controlled line spacing, angle, and additional stylistic options.
- Parameters:
dist
(Number): The distance between hatching lines, in canvas units.angle
(Number): The angle at which hatching lines are drawn. The angle mode (degrees or radians) is set by p5'sangleMode()
.options
(Object): Optional settings to affect the hatching style, including:rand
: Randomness in line placement (0 to 1 or false).continuous
: Whether to connect the end of a line with the start of the next.gradient
: Modifies the distance between lines to create a gradient effect (0 to 1 or false).- Defaults to
{rand: false, continuous: false, gradient: false}
.
- Usage:
// Set hatching with specific distance, angle, and options brush.hatch(5, 30, {rand: 0.1, continuous: true, gradient: 0.3});
brush.noHatch()
- Description: Disables hatching for subsequent shapes. Use this function to return to normal drawing modes without hatching.
- Usage:
// Disable hatching for upcoming shapes brush.noHatch();
brush.setHatch(brushName, color, weight)
- Description: Sets the brush type, color, and weight specifically for hatching. If not called, hatching will use the parameters defined by the current stroke settings.
- Parameters:
brushName
(String): The name of the brush to use for hatching.color
(String|p5.Color): The color for the brush, either as a CSS string or a p5.Color object.weight
(Number): The weight or size of the brush for hatching.
- Usage:
// Set the hatching brush to "rotring" with green color and specific weight brush.setHatch("rotring", "green", 1.3);
In essence, the hatching system activates hatches for subsequent shapes, similarly to stroke and fill operations. However, you can also directly hatch multiple objects at once (and their intersections), if you proceed as described below .
brush.hatchArray(polygons)
- Description: Creates a hatching pattern across specified polygons. This function applies the set hatching parameters to a single polygon or an array of polygons.
- Parameters:
polygons
(Array|Object): The polygon(s) to apply the hatching. Can be a single polygon object or an array of polygon objects.
- Note: This is not the main, but an alternative way of applying hatches. Read above.
- Usage:
// Define an array of polygons (reference in the classes section) let myPolygons = [] for (let i = 0; i < 10; i++) { // We're creating 10 random triangles here let p = new brush.Polygon([ [random(width), random(height)], [random(width), random(height)], [random(width), random(height)], ]) myPolygons.push(p) } // Create hatching across specified polygons brush.hatchArray(myPolygons);
brush.hatchArray()
provides an efficient way to apply complex hatching patterns to a set of defined shapes.
This section details the functions for creating various shapes and strokes with the set brush, fill, and hatch parameters.
The following functions are only affected by stroke() operations, completely ignoring fill() and hatch().
brush.line(x1, y1, x2, y2)
- Description: Draws a line from one point to another using the current brush settings. This function is affected only by stroke operations and will not produce any drawing if
noStroke()
has been called. - Parameters:
x1
(Number): The x-coordinate of the start point.y1
(Number): The y-coordinate of the start point.x2
(Number): The x-coordinate of the end point.y2
(Number): The y-coordinate of the end point.
- Usage:
// Set the brush color and draw a line brush.stroke("red"); brush.line(15, 10, 200, 10);
- Description: Draws a line from one point to another using the current brush settings. This function is affected only by stroke operations and will not produce any drawing if
brush.flowLine(x, y, length, dir)
- Description: Draws a flow line that adheres to the currently selected vector field. Flow lines are defined by a starting point, length, and direction. They are useful for creating strokes that dynamically follow the flow of the vector field.
- Parameters:
x
(Number): The x-coordinate of the starting point.y
(Number): The y-coordinate of the starting point.length
(Number): The length of the line.dir
(Number): The direction in which to draw the line, measured anticlockwise from the x-axis.
- Usage:
// Set a vector field and draw a flow line brush.field("seabed"); brush.flowLine(15, 10, 185, 0);
These three functions provide advanced control over the creation of strokes/paths, allowing for custom pressure and direction at different points along the path. This is a strange way of defining strokes, but intuitive when you think of them as bodily movements performed with the hands. You can create two types of strokes: "curve" or "segments". For curved strokes, the curvature at any point of the stroke is lerped between the nearest control points.
These functions allow for the creation of strokes with varied pressures and directions, mimicking the organic nature of hand-drawn strokes. For an application of these principles, see: Enfantines II
-
brush.beginStroke(type, x, y)
- Description: Initializes a new stroke, setting the type and starting position. The type determines the kind of Plot to create, either a "curve" or "segments".
- Parameters:
type
(String): The type of the stroke, either "curve" or "segments".x
(Number): The x-coordinate of the starting point of the stroke.y
(Number): The y-coordinate of the starting point of the stroke.
- Usage:
// Begin a new curve stroke brush.beginStroke("curve", 15, 30);
-
brush.segment(angle, length, pressure)
- Description: Adds a segment to the stroke, defining its path by specifying the angle, length, and pressure. This function is used after
brush.beginStroke()
and beforebrush.endStroke()
to outline the stroke's trajectory and characteristics. - Parameters:
angle
(Number): The initial angle of the segment, relative to the canvas, measured anticlockwise from the x-axis.length
(Number): The length of the segment.pressure
(Number): The pressure at the start of the segment, influencing properties like width.
- Usage:
// Add two segments to the stroke brush.segment(30, 150, 0.6); brush.segment(75, 40, 1.1);
- Description: Adds a segment to the stroke, defining its path by specifying the angle, length, and pressure. This function is used after
-
brush.endStroke(angle, pressure)
- Description: Completes the stroke path and triggers its rendering. This function defines the angle and pressure at the last point of the stroke path.
- Parameters:
angle
(Number): The angle of the curve at the end point of the stroke path.pressure
(Number): The pressure at the end of the stroke.
- Usage:
// Complete the stroke with a specific angle and pressure brush.endStroke(-45, 0.8);
brush.spline(array_points, curvature)
- Description: Generates and draws a spline curve, a smooth curve defined by a series of control points. The curve connects the start and end points directly, using the other points in the array as control points to define the curve's path. The curvature parameter allows for adjusting the smoothness of the curve. Spline is maybe not the appropriate description, since these splines are basically segmented paths with rounded corners.
- Parameters:
array_points
(Array<Array>): An array of points, where each point is an array of two numbers[x, y]
.curvature
(Number): Optional. The curvature of the spline curve, ranging from 0 to 1. A curvature of 0 results in a series of straight segments.
- Note: This is a simplified alternative to beginShape() - endShape() operations, useful for certain stroke() applications.
- Usage:
// Define points for the spline curve let points = [[30, 70], [85, 20], [130, 100], [180, 50]]; // Create a spline curve with a specified curvature brush.spline(points, 0.5);
brush.plot(p, x, y, scale)
- Description: Renders a predefined shape or plot with a flowing brush stroke, following the currently active vector field. The shape is drawn at a specified starting position and scale. The plot object should be defined following the instructions in the Exposed Classes section.
- Parameters:
p
(Plot Object): A plot object representing the shape.x
(Number): The x-coordinate of the starting position.y
(Number): The y-coordinate of the starting position.scale
(Number): The scale at which to draw the shape.
- Note: This is an alternative to beginStroke() - endStroke() operations. It is useful for drawing the same Plot at different starting points and scales.
- Usage:
// Define a plot (heart shape) let heart = new brush.Plot(); // ... Define the heart plot here ... // Draw the heart shape with a flowing stroke brush.flowShape(heart, 200, 200, 1.3);
The following functions are affected by stroke(), fill() and hatch() operations.
brush.rect(x, y, w, h, mode)
- Description: Draws a rectangle on the canvas. This shape adheres to the current stroke, fill, and hatch attributes. Rectangles are influenced by active vector fields.
- Parameters:
x
(Number): The x-coordinate of the rectangle.y
(Number): The y-coordinate of the rectangle.w
(Number): The width of the rectangle.h
(Number): The height of the rectangle.mode
(Boolean): Optional. IfCENTER
, the rectangle is drawn centered at(x, y)
.
- Usage:
brush.noStroke(); brush.noHatch(); brush.fill("#002185", 75); brush.rect(150, 100, 50, 35, CENTER);
brush.circle(x, y, radius, r)
- Description: Draws a circle on the canvas, using the current brush settings. If
r
is true, the circle is rendered with a hand-drawn style. Circles are affected by vector fields. - Parameters:
x
(Number): The x-coordinate of the circle's center.y
(Number): The y-coordinate of the circle's center.radius
(Number): The radius of the circle.r
(Boolean): Optional. When true, applies a hand-drawn style to the circle.
- Usage:
brush.circle(100, 150, 75, true);
- Description: Draws a circle on the canvas, using the current brush settings. If
These three functions perform similarly to the p5.js beginShape(), vertex(), and endShape() functions, althouh curvature calculation is very different. These allow you to draw custom shapes, with fine control over brush pressure at the different points of the perimeter.
-
brush.beginShape(curvature)
- Description: Initiates the creation of a custom shape by starting to record vertices. An optional curvature can be defined for the vertices.
- Parameters:
curvature
(Number): Optional. A value from 0 to 1 that defines the curvature of the shape's edges.
- Returns: None.
- Usage:
// Begin defining a custom shape with a specified curvature brush.beginShape(0.3);
-
brush.vertex(x, y, pressure)
- Description: Adds a vertex to the custom shape currently being defined. The function is used between
brush.beginShape()
andbrush.endShape()
calls. An optional pressure parameter can be applied at each vertex. - Parameters:
x
(Number): The x-coordinate of the vertex.y
(Number): The y-coordinate of the vertex.pressure
(Number): Optional. The pressure at the vertex, affecting properties like width.
- Returns: None.
- Usage:
// Add vertices to the custom shape brush.vertex(50, 100); brush.vertex(100, 150, 0.5); brush.vertex(150, 100);
- Description: Adds a vertex to the custom shape currently being defined. The function is used between
-
brush.endShape(a)
- Description: Completes the custom shape, finalizing the recording of vertices. The shape can be either closed or left open based on the optional argument. The function also triggers the rendering of the shape with the current stroke, fill, and hatch settings.
- Parameters:
a
(String): Optional. If set toCLOSE
, the shape is closed.
- Returns: None.
- Usage:
// Finish the custom shape and close it with a straight line brush.endShape(CLOSE);
brush.polygon(pointsArray)
- Description: Creates and draws a polygon based on a provided array of points. This function is useful for drawing shapes that are not affected by vector fields, offering an alternative to the
beginShape()
andendShape()
approach. - Parameters:
pointsArray
(Array): An array of points, where each point is an array of two numbers[x, y]
.
- Note: This is a simplified alternative to beginShape() - endShape() operations, useful for certain fill() and hatch() applications.
- Usage:
// Define a polygon using an array of points let points = [[x1, y1], [x2, y2], ...]; brush.polygon(points);
brush.polygon()
is ideal for drawing fixed shapes that remain unaffected by vector fields, providing precise control over their form and appearance.
- Description: Creates and draws a polygon based on a provided array of points. This function is useful for drawing shapes that are not affected by vector fields, offering an alternative to the
This section covers functions for initializing the drawing system, preloading required assets, and configuring system behavior. By default, the library works without executing these functions, but you might want to configure them to your liking.
brush.seed(seed)
- Description: Sets a custom seed for deterministic drawing results.
- Parameters:
seed
(String | Number): A seed.
- Example:
Replace
brush.seed('hello');
hello
with the actual seed.
brush.load(canvasID)
- Description: Initializes the drawing system and sets up the environment. If
canvasID
is not provided, the current window is used as the rendering context. If you want to load the library on a custom p5.Graphics element, you can do it by executing this function. - Parameters:
canvasID
(string): Optional ID of the buffer/canvas element. If false, uses the window's rendering context.
- Example (load p5.brush on buffer):
function setup() { createCanvas(400, 400, WEBGL) // Draw stuff to global canvas brush.set("HB","black",1) brush.rect(40,40,150,100) // Force draw stuff to canvas brush.reDraw() // Create buffer let buffer = createGraphics(200, 300, WEBGL) brush.load(buffer) brush.set("HB","black",1) brush.rect(40,40,150,100) // Force draw stuff to buffer brush.reDraw() image(buffer,20,40) // Load p5.brush again on global canvas brush.load() }
- Note for Instance Mode: If you want to use the p5 instance mode, you need to pass the proper variable as canvasID.
let sketch = function(p) { let x = 100; let y = 100; // Register instance method here, sending your function arg p brush.instance(p) p.setup = function() { p.createCanvas(700, 410); }; p.draw = function() { p.background(0); brush.fill("red", 75); brush.rect(x, y, 50, 50); }; }; let myp5 = new p5(sketch);
- Description: Initializes the drawing system and sets up the environment. If
brush.preload()
- Description: Preloads necessary assets or configurations for brushes. If you are using custom image tip brushes, you need to include this question within the preload() function of your p5 sketch.
- Parameters: None
- Example: To use a deterministic random number generator, such as one from a generative art platform like fx(hash), you might configure your system as follows:
// Your p5 preload function function preload () { brush.preload() // Add this if you want to use custom img brushes }
brush.colorCache(bool = true)
- Description: Enables or disables color caching for WebGL shaders. Color caching can increase performance but may produce less accurate textures when the same color is used repeatedly. It's set to true by default
- Parameters:
bool
(boolean): Set to true to enable caching, or false to disable it.
brush.scaleBrushes(scale)
- Description: Adjusts the global scale of all standard brush parameters, including weight, vibration, and spacing, based on the given scaling factor. This function is specifically designed to affect default brushes only, allowing for uniform scaling across various brush types.
- Parameters:
scale
(Number): The scaling factor to be applied to the brush parameters.
- Note: This function only impacts the default brushes. Custom brushes may not be affected by this scaling, since they are defined per case basis.
- Usage:
Using
// Scale all standard brushes by a factor of 1.5 brush.scaleBrushes(1.5);
brush.scaleBrushes()
, you can easily adjust the size and spacing characteristics of standard brushes in your project, providing a convenient way to adapt to different canvas sizes or artistic styles.
brush.remove()
- Description: Removes brush library brushes and unloads the library. This can be useful if you only used the library to draw into a buffer, and you want to perform only normal p5 operations after that.
brush.instance(p)
- Description: Execute before the setup() and draw() functions if you need to use p5 in instance mode
- Parameters:
p
(variable): Variable used as the function argument. See below
- Example:
let sketch = function(p) { let x = 100; let y = 100; // Register instance method here, sending your function arg p brush.instance(p) p.setup = function() { p.createCanvas(700, 410); }; p.draw = function() { p.background(0); brush.fill("red", 75); brush.rect(x, y, 50, 50); }; }; let myp5 = new p5(sketch);
Exposed Classes provide foundational elements for creating and manipulating shapes and paths, as well as interacting with vector-fields in a more advanced manner.
-
Description: Represents a polygon defined by a set of vertices. The
Polygon
class is essential for creating and working with multi-sided shapes, offering various methods to manipulate and render these shapes. -
Constructor:
brush.Polygon(pointsArray)
pointsArray
(Array): An array of points, where each point is an array of two numbers[x, y]
.
-
Methods:
.intersect(line)
- Intersects the polygon with a given line, returning all intersection points.
- Parameters:
line
(Object): A line object with propertiespoint1
andpoint2
.
- Returns:
Array
of objects, each withx
andy
properties, representing the intersection points.
.draw(brush, color, weight)
- Draws the polygon on the canvas, following the current stroke state or the provided params.
.fill(color, opacity, bleed, texture)
- Fills the polygon on the canvas, adhering to the current fill state or to the provided params.
.hatch(distance, angle, options)
- Applies hatching to the polygon on the canvas, based on the current hatch state or the provided params.
-
Attributes:
.vertices
: An array of the polygon's vertices, each vertex being an object withx
andy
properties..sides
: An array representing the different segments that make up the polygon.
-
Description: The
Plot
class is crucial for the plot system, managing a collection of segments to create a variety of shapes and paths. It enables intricate designs, such as curves and custom strokes, by defining each segment with an angle, length, and pressure.Plot
instances can be transformed through rotation, and their appearance controlled via pressure and angle calculations. -
Constructor:
brush.Plot(_type)
_type
(String): The type of plot, either "curve" or "segments".
-
Methods:
.addSegment(_a, _length, _pres)
- Adds a segment to the plot.
- Parameters:
_a
(Number): The angle of the segment._length
(Number): The length of the segment._pres
(Number): The pressure of the segment.
.endPlot(_a, _pres)
- Finalizes the plot with the last angle and pressure.
- Parameters:
_a
(Number): The final angle of the plot._pres
(Number): The final pressure of the plot.
.rotate(_a)
- Rotates the entire plot by a specified angle.
- Parameters:
_a
(Number): The angle for rotation.
.genPol(_x, _y)
- Generates a polygon based on the plot.
- Parameters:
_x
(Number): The x-coordinate for the starting point._y
(Number): The y-coordinate for the starting point.
- Returns:
Polygon
- The generated polygon.
.draw(x, y)
- Draws the plot on the canvas with current stroke() state.
- Parameters:
x
(Number): The x-coordinate to draw at.y
(Number): The y-coordinate to draw at.
.fill(x, y)
- Fills the plot on the canvas with current fill() state.
- Parameters:
x
(Number): The x-coordinate to fill at.y
(Number): The y-coordinate to fill at.
.hatch(x, y)
- Hatches the plot on the canvas with current hatch() state.
- Parameters:
x
(Number): The x-coordinate to hatch at.y
(Number): The y-coordinate to hatch at.
-
Attributes:
.segments
: An array containing the lengths of all segments..angles
: An array of angles at the different control points..press
: An array with custom brush pressures at the various control points..type
: The type of the plot, either "curve" or "segments"..pol
: Stores the generated polygon object after executing the.genPol()
method.
-
Description: The
Position
class represents a point within a two-dimensional space, capable of interacting with a vector field. It includes methods for updating the position based on the field's flow, allowing for movement through the vector field in various ways. -
Constructor:
brush.Position(x, y)
x
(Number): The initial x-coordinate.y
(Number): The initial y-coordinate.
-
Methods:
.moveTo(_length, _dir, _step_length, isFlow)
- Moves the position along the flow field by a specified length.
- Parameters:
_length
(Number): The length to move along the field._dir
(Number): The direction of movement, with angles measured anticlockwise from the x-axis._step_length
(Number): The length of each step.isFlow
(Boolean): Whether to use the flow field for movement.
.plotTo(_plot, _length, _step_length, _scale)
- Plots a point to another position within the flow field, following a given
Plot
object. - Parameters:
_plot
(Position): ThePlot
path object._length
(Number): The length to move towards the target position._step_length
(Number): The length of each step._scale
(Number): The scaling factor for the plotting path.
- Plots a point to another position within the flow field, following a given
.angle()
- Returns vector-field angle for that position.
.reset()
- Resets the
plotted
property to 0. This property tracks the distance moved since the last reset or the creation of the position. Important for consecutive differentPlot
paths.
- Resets the
-
Attributes:
.x
: The current x-coordinate..y
: The current y-coordinate..plotted
: Stores the distance moved since the last reset or the creation of the position.
- Basic examples: collection in p5.editor (more soon)
- GenArt project 1: Enfantines I
- GenArt project 2: Enfantines II
- GenArt project 3: Fuga a tientas
We welcome contributions from the community. If you find a bug or have a feature request, please open an issue on Github.
p5.brush.js is released under the MIT License. See the LICENSE file for details.
- The fill() operations followed the steps explained by Tyler Hobbs here
- The realistic color blending is calculated with spectral.js, by Ronald van Wijnen
- Several p5 bugs that impacted the library have been found and solved with the help of Dave Pagurek