p5.plotsvg

repository·main·Indexed 42 days ago

https://github.com/golanlevin/p5.plotsvg

A Plotter-Oriented SVG Exporter for p5.js version 0.3.0, designed for physical vector output devices like pen plotters and laser cutters. It provides an API to record p5.js drawing commands into clean, path-based SVG geometry using beginRecordSvg() and endRecordSvg(). Features include grouping strokes by color, coordinate precision control, and techniques for approximating fills via hatching lines.

Tokens
13.9K
Snippets
44
Records
73
Agent score
52%

What's inside p5.plotsvg

  1. What is p5.plotSvg?

    main

    p5.plotSvg is a p5.js library designed to export SVG files specifically tailored for path-based vector output devices like pen plotters (e.g., AxiDraw), laser cutters, and CNC machines.

    Key Characteristics

    • Geometry-focused: It focuses on the geometry of paths rather than visual styling. It assumes the final appearance is determined by the physical tool used.
    • Non-intrusive: It does not interfere with graphics performance during animations.
    • Machine-friendly: It includes features like filtering degenerate paths, sanitizing numeric values, clamping coordinates, and controlling decimal precision.
    • Plotting Workflows: Supports Inkscape-compatible layer metadata, SVG group naming/merging, and grouping by stroke-color to support multi-pen workflows.

    Compatibility

    • p5.js: Compatible with versions 1.4.2 through 1.11.13. Support for p5.js v2 is available for most 2D geometry export and is under active development for newer v2 curve and spline features.
  2. Explore p5.plotSvg usage patterns and examples

    main

    The examples/ directory contains a variety of demonstrations for generating plotter-friendly SVGs. Key patterns include:

    • Static Mode: Drawing all art within setup() only (plotSvg_hello_static).
    • Animated/Interactive Mode: Using setup(), draw(), and user input (like keypresses) to capture an SVG during an animation (plotSvg_hello_animating, plotSvg_generative).
    • Add-on API: Using the add-on-style API across different p5.js versions (v1 and v2) and modes (global and instance) (plotSvg_addon_example).
    • Instance Mode: Integrating p5.plotSvg when using p5.js in instance mode (plotSvg_instancemode).
    • Advanced Plotting Techniques:
      • Hatched Shapes: A technique for exporting filled/hatched SVG shapes suitable for plotters (plotSvg_hatched_shapes).
      • Post-Grouping: Merging groups of paths computed at different times to create per-color layers (plotSvg_post_grouping).
      • Typography: Using inlined Hershey fonts for simple typography without external files (plotSvg_inline_hershey_text) or loading monoline SVG fonts (plotSvg_svg_font_text).
    • Accumulation Patterns: Recording user marks (plotSvg_drawing_recorder) or accumulating particle traces over time (plotSvg_particle_paths).
  3. Understand the p5.plotSvg architectural model

    main
    p5.plotSvg is designed as a non-intrusive capture tool rather than a custom renderer. It does not replace the standard p5.js drawing process. Instead, you draw normally to the p5 canvas, and the library captures those drawing commands specifically during explicit SVG recording sessions. This ensures that your canvas output and SVG output remain consistent with standard p5.js behavior.
  4. Understand the scope and limitations of p5.plotSvg

    main

    p5.plotSvg is a specialized SVG exporter designed specifically for pen-plotters. It is NOT a general-purpose SVG exporter or a browser-based SVG renderer.

    What it is NOT:

    • A general-purpose exporter: It purposefully omits features that have no analogue in pen-plotting, such as pixel-based images, transparency, filters, shaders, blend modes, gradients, animation, or fills/stroke weights.
    • An SVG renderer: It does not replace the p5.js canvas; it exports the geometric paths you draw to an SVG file.
    • An SVG loader: It cannot be used to load or parse SVG files into p5.js.
    • An optimizer: It does not perform geometry optimization (like TSP for path ordering, merging segments into polylines, or de-duplicating lines). Use tools like vpype or Deepnest for this.
    • A vectorizer: It does not convert pixel data (like dithering or hatching) into vectors. Only vector-based commands like line() and ellipse() are exported.
    • A computational geometry library: It does not handle offset curves, intersections, or clipping.
  5. How to record SVG in p5.js Instance Mode

    main

    When working in instance mode, the beginRecordSvg and endRecordSvg functions require the p5 instance to correctly scope the drawing commands.

    • p5plot.beginRecordSvg(p, filename): Starts the SVG recording. p is your p5 instance.
    • p5plot.endRecordSvg(): Ends the recording. Note that in the elaborated example, if beginRecordSvg is called via a shorthand (if available in the scope), it still relies on the instance passed during initialization.
    // Inside a p5 instance sketch
    p.setup = function() {
      p.createCanvas(400, 400);    
      p5plot.beginRecordSvg(p, "output.svg");
      p.circle(200, 200, 200);
      p5plot.endRecordSvg();
    };
  6. Alternative: Use inlined single-line fonts

    main
    If you want to avoid the complexity of loading external SVG 1.1 font files, you can use a simplified approach where a basic single-line font is reformatted and directly inlined (hardcoded) into your p5.plotSVG project. This eliminates the need for external font file loading and is useful for lightweight or standalone sketches.
  7. What p5.plotSvg does NOT support

    main

    To maintain plotter-safe stability, the following features are explicitly not supported for SVG export:

    • Clipping: clip(), beginClip(), and endClip() are not implemented for SVG export. Implementing these would require complex computational geometry and path splitting.
    • Custom Renderer Mode: The library is not a custom renderer; it captures commands from the standard p5.js drawing flow.
  8. Use experimental extension hooks for advanced SVG output

    main

    For advanced users building add-ons, p5.plotSvg exposes low-level hooks to manipulate the SVG output during an active recording session (between beginRecordSvg() and endRecordSvg()).

    • Command Access: p5plotSvg._commands provides access to the live internal command array. You can inspect or append compatible command objects here.
    • Constants: Use the read-only p5plotSvg.SVG_COMMAND and p5plotSvg.SVG_SEGMENT constants to identify command and segment type strings.
    • Available Hooks:
      • injectSvgHeaderAttribute()
      • injectSvgDef()
      • setSvgExportPolylinesAsPaths()
      • Adding custom attributes arrays to injected command objects.
  9. Use p5.plotSvg with ESM (ECMAScript Modules)

    main

    For modern JavaScript projects, you can import p5.plotSvg from npm or a CDN. If you are using p5.js v2, you must register the plotSvgAddon before creating your sketch.

    Steps for p5.js v2:

    1. Import p5 and plotSvgAddon from p5.plotsvg.
    2. Call p5.registerAddon(plotSvgAddon).
    3. Create your sketch using new p5().

    The default export is the p5plotSvg namespace, which remains available for namespace-style calls.

    import p5 from 'p5';
    import { plotSvgAddon } from 'p5.plotsvg';
    
    p5.registerAddon(plotSvgAddon);
    
    new p5((sketch) => {
      sketch.setup = function() {
        sketch.createCanvas(400, 400);
        sketch.beginRecordSvg("output.svg");
        sketch.line(20, 20, 380, 380);
        sketch.endRecordSvg();
      };
    });
  10. Use p5.plotSvg in p5.js Instance Mode

    main

    To use p5.plotSvg within a p5.js instance (namespaced mode), you must pass the p5 instance (the context or sketch object) as the first argument to the recording functions. This is required when building modern web applications (e.g., with React) or when running multiple sketches on a single page.

    Important Limitation: Do not use the same import of p5plot for different instances. Each sketch should import p5.plotsvg in its own separate JavaScript module to avoid conflicts.

    import p5plot from 'p5.plotsvg';
    
    function sketch(p) {
      p.setup = function() {
        p.createCanvas(400, 400);    
        // Pass the p5 instance 'p' as the first argument
        p5plot.beginRecordSvg(p, "output.svg");
        p.circle(200, 200, 200);
        p5plot.endRecordSvg();
      };
    }
    
    new p5(sketch, document.getElementById("container"));
  11. Install p5.plotSvg via script tags

    main

    You can include p5.plotSvg.js in your project alongside p5.js using a CDN or a local copy. The specific script to use depends on whether you are using p5.js v1 or v2.

    For p5.js v1: Use the standard p5.plotSvg.js build.

    For p5.js v2: Use the p5.plotSvg.js build located in the dist/ directory.

    Available CDNs:

    • https://unpkg.com/p5.plotsvg@latest/lib/p5.plotSvg.js
    • https://cdn.jsdelivr.net/npm/p5.plotsvg@latest/lib/p5.plotSvg.js
    <!-- For p5.js v1 -->
    <script src="https://cdn.jsdelivr.net/npm/p5@1.11.13/lib/p5.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/p5.plotsvg@latest/lib/p5.plotSvg.js"></script>
    
    <!-- For p5.js v2 -->
    <script src="https://cdn.jsdelivr.net/npm/p5@2.3.0/lib/p5.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/p5.plotsvg@latest/dist/p5.plotSvg.js"></script>
  12. Export SVG in p5.js Global Mode

    main

    In global mode, you can use the add-on-style functions beginRecordSvg(filename) and endRecordSvg() to wrap your drawing commands. This allows you to capture specific frames or moments in your draw() loop as SVG files.

    Workflow:

    1. Call beginRecordSvg("filename.svg") to start recording.
    2. Execute your p5.js drawing commands (e.g., line(), circle()).
    3. Call endRecordSvg() to finalize and save the file.

    Note: For backward compatibility, older sketches can use beginRecordSvg(this, "filename.svg").

    Recommended Post-Processing: After generating an SVG, it is recommended to optimize it for plotting using the vpype command-line utility.

    // This is the sketch.js file in global mode.
    
    function setup(){
      createCanvas(816, 1056); 
    }
    
    function draw(){
      background(255); 
      
      // Example: Exporting on a specific condition
      if (someCondition) {
        beginRecordSvg("myOutput.svg");
        line(0, 0, mouseX, mouseY); 
        endRecordSvg();
      }
    }