p5.svg is an experimental native vector graphics system provided in p5.js starting from version 2.4. It allows you to create, import, and export vector graphics directly in p5.js without needing external addons. With p5.svg, artists, designers, and educators can generate graphics that scale smoothly for high-DPI displays, print, pen plotters, CNC routers, laser cutters, and embroidery machines using familiar p5.js drawing functions.
The specifics of these APIs are currently experimental and subject to evolution based on community feedback. A valuable contribution to the project is testing these APIs, reporting edge cases, and sharing feedback on usability and performance!
Project Goals
p5.svg addresses several key goals:
- Vector Graphics:
p5.svgallows p5.js drawings to be saved as vector graphics that can scale to different sizes without losing sharpness. - Familiar p5 Drawing Workflow: To create SVG output, the only thing you need to do differently is use
createShape()andbuildShape(). Inside these functions, use the standard drawing API (rect,circle,path,fill,stroke,translate,rotate, etc.) as you usually would. - Import and Export SVG Files:
p5.svgallows you to load existing SVG files withloadSVG()and save p5.js drawings as SVG files usingsaveSVG()orgetSVG().
What Needs Feedback
The main ways you can help develop p5.svg are:
- Shape API: Test vector shape functions like
createSVG(),loadSVG(),buildShape(),createShape(),shape(),getSVG(), andsaveSVG(). We want feedback on whether the API feels familiar to someone learning p5.js, whether the functions are easy to understand for beginners, and whether they are easy to use when teaching p5.js. Let us know if any choices feel confusing or tricky for students, or if anything feels inconsistent with the rest of p5.js. - SVG Path Parsing: Test importing SVGs generated by vector design tools (Adobe Illustrator, Inkscape, Figma). Report any unsupported path commands (
M,L,H,V,C,S,Q,T,A,Z) or malformed elements. - Styling and CSS Properties: Help verify that stroke weights, colors, fill rules, opacities, gradients, and transform stacks behave consistently across export and import pipelines.
- Performance & Memory: Test large or complex SVG scenes to help identify bottlenecks in DOM parsing, AST construction, or XML string generation.
Technical Overview
Behind the scenes, p5.svg operates in three main layers:
Shape Recording (
src/shape/svg/svg_recorder.js):- Intercepts 2D drawing calls (
rect,ellipse,line,beginShape/endShape,fill,stroke,push,pop,translate,rotate,scale,applyMatrix). - Builds an Abstract Syntax Tree (AST) composed of node instances (
ScopeNode,ShapeNode,BackgroundNode,ClearNode,ImageNode). - Tracks coordinate transformations using an internal
TransformStack.
- Intercepts 2D drawing calls (
SVG Export & Visitor (
src/shape/svg/svg_export.js):- Implements
SVGExportAddonandSVGVisitor(extendingp5.PrimitiveVisitor). - Traverses the shape AST to output standard SVG 2.0 XML markup string via
getSVG()or triggers browser file downloads viasaveSVG().
- Implements
SVG Import & Parsing (
src/shape/svg/svg_import.js):- Implements
SVGImportAddonto parse external SVG DOM trees. - Tokenizes path data commands (
PATH_COMMANDS) and converts SVG elements (<path>,<rect>,<circle>,<ellipse>,<line>,<polyline>,<polygon>,<g>) into internal p5ShapeCollectionstructures ready for playback viashape().
- Implements
Usage Example
Exporting an SVG
function setup() {
createCanvas(400, 400);
// Record drawing commands into a vector shape
const record = buildShape(() => {
background(245);
fill(99, 102, 241);
stroke(0);
strokeWeight(2);
circle(200, 200, 150);
});
// Save as vector file
saveSVG(record, 'my-vector.svg');
}Importing and Replaying an SVG
let botLogo;
async function setup() {
createCanvas(500, 500);
try {
// loadSVG returns a promise; await the resolved ShapeCollection
botLogo = await loadSVG('assets/robot.svg');
console.log('SVG Loaded successfully!');
} catch (err) {
console.error('Failed to load SVG:', err);
}
}
function draw() {
background(255);
// Render the SVG once it is fully loaded
if (botLogo) {
shape(botLogo, 100, 100);
} else {
fill(100);
text('Loading SVG...', 20, 30);
}
}Contributing
We welcome contributions to p5.svg! You can get involved by:
- Testing existing SVG workflows and reporting bugs or unexpected behavior on GitHub.
- Proposing and implementing new SVG features, such as expanded SVG element support, clipping paths, gradients, filters, and custom SVG attributes.
- Improving SVG import and parsing, including support for additional path commands and CSS/SVG attributes.
- Adding tests and examples to validate new functionality and demonstrate real-world SVG workflows.
- Creating tutorials and creative coding examples that showcase how
p5.svgcan be used in p5.js projects. - Reviewing and providing feedback on experimental APIs to help improve their usability, consistency, and performance.