Contribute p5.svg Overview

p5.svg Overview

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.svg allows 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() and buildShape(). 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.svg allows you to load existing SVG files with loadSVG() and save p5.js drawings as SVG files using saveSVG() or getSVG().

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(), and saveSVG(). 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:

  1. 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.
  2. SVG Export & Visitor (src/shape/svg/svg_export.js):

    • Implements SVGExportAddon and SVGVisitor (extending p5.PrimitiveVisitor).
    • Traverses the shape AST to output standard SVG 2.0 XML markup string via getSVG() or triggers browser file downloads via saveSVG().
  3. SVG Import & Parsing (src/shape/svg/svg_import.js):

    • Implements SVGImportAddon to 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 p5 ShapeCollection structures ready for playback via shape().

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.svg can be used in p5.js projects.
  • Reviewing and providing feedback on experimental APIs to help improve their usability, consistency, and performance.