Pure GPU, instanced, screen-projected lines for regl
This module implements a very general command for drawing lines using the regl WebGL library.
Architecturally this module has two goals:
- Data may live on the GPU.
 - Minimize unnecessary constraints.
 
To accomplish this, it implements a simple pragma-based interface for specifying how your attributes connect to line properties and to varyings.
Features:
- Configure your own attributes, varyings, uniforms, and shaders
 - Compute position and line width in the vertex shader
 - GPU computation of round joins, bevels, and miters (with miter limit), and square and rounded end caps.
 - Optional end cap insertion, using 
position.w == 0.0or alternativelyposition.xNaN to signal a line break (see: docs/multiple.html) - Regl-compatible attribute specification with strides and offsets
 - Forward additional regl configuration to the draw command
 - Seamlessly permits substitution of Vertex Array Objects (VAOs)
 - 13.4 KB minified, 5.3 KB gzipped. No dependencies (although it is expected to be used together with regl, which requirement I'd like to consider removing)
 
Limitations:
ANGLE_instanced_arraysextension is required (which ought to be universally supported)- Width is best varied slowly as line joins to not take into account varying width
 - Automatic end cap insertion wastes vertices when the cap resolution exceeds the join resolution
 - Line dashes are not built-in, but you can easily build them yourself
 
The dist/ directory contains UMD bundles, or you may use from a CDN, e.g. https://unpkg.com/regl-gpu-lines@latest. Both expose the module as reglLines.
Otherwise install from npm:
npm install regl-gpu-linesSee API documentation.
- Basic example: A minimal example. Just a line.
 - Variable width: A basic line with variable width and color
 - Multiple lines: Use position NaN to break up lines into multiple segments
 - Depth: Layer lines using the z-coordinate
 - Closed loop: Create a closed loop by omitting end caps and repeating the first three vertices at the end.
 - Line border: Use 
lineCoordto draw a SDF line border - Interleaved attributes: Instead of a regl buffer, you can pass a regl-style attribute description with 
buffer,stride,offset, anddivisorproperties in order to used interleaved, packed attribute data. - Torus knot: A torus knot with layering which can be difficult to draw with SVG.
 - Batched rendering: Illustrates how to take advantage of 
reorder: trueto reduce shader program changes from, in this example, thirty to four. - Post-projection: Illustrates post-project to draw lines projected onto a plane from some other angle.
 - Vertex Array Object (VAO): Illustrates seamless swapping of VAO for vertex and endpoint attributes.
 - Fake instancing: Sort of allows you to mimic instanced rendering on top of instanced rendering, albeit with some duplication of data.
 - Debug page: Shows how to use 
instanceIDandtriStripCoordvaryings to draw a wireframe - Full debug view: A page for exploring all the bells and whistles
 - GPGPU Strange Attractors: Feed a GPU particle simulation from texture data directly into line rendering
 
A minimal example looks like the following, where a vec2 attribute xy is connected to line position via a GLSL #pragma.
const drawLines = reglLines(regl, {
  vert: `
    precision highp float;
    #pragma lines: attribute vec2 xy;
    #pragma lines: position = getPosition(xy);
    vec4 getPosition(vec2 xy) { return vec4(xy, 0, 1); }
    #pragma lines: width = getWidth();
    uniform float width;
    float getWidth() { return width; }`,
  frag: `
    precision lowp float;
    void main () {
      gl_FragColor = vec4(1);
    }`,
  uniforms: {
    width: (ctx, props) => props.customWidth * ctx.pixelRatio
  }
});
const xy = [[-1, 1], [-0.5, -1], [0, 1], [0.5, -1], [1, 1]];
const lineData = {
  customWidth: 20,
  join: 'round',
  cap: 'round',
  vertexCount: xy.length,
  vertexAttributes: {
    xy: regl.buffer(xy)
  },
  endpointCount: 2,
  endpointAttributes: {
    xy: regl.buffer([xy.slice(0, 3), xy.slice(-3).reverse()])
  }
};
drawLines(lineData);Serve example pages—e.g. the example in examples/closed-loop.js—with
npm start closed-loopRun live-reloading render tests with
npm run serve-render-testsExecuting the render tests from the CLI requires the headless-gl module. You may use nodemon to live-run the render tests when the code is changed.
npm install -g nodemon
nodemon test/render.jsFilter tests with
FILTER=miter/basic nodemon test/render.jsand update expectation images with
UPDATE=1 FILTER=miter/basic node test/render.jsYou may view the tests, run against the latest version from unpkg.com, at https://rreusser.github.io/regl-gpu-lines/docs/tests.html
- regl-line2d: The line rendering library used by Plotly.js. If you want production quality lines, you should go here.
 - regl-line: A regl function to draw flat 2D and 3D lines.
 - regl-insta-lines: A very clear and well-written module. Very close to what I was searching for. My main desire was to defer more of the configuration to runtime and to avoid overlap in the miters.
 - screen-projected-lines: An excellent, concise module for screen-projected lines. Without joins or caps, such lines are much simpler.
 - Drawing Lines is Hard: Matt DesLaurier's classic post on the topic of drawing lines.
 - Instanced Line Rendering Part I: Rye Terrell first blog post on the topic.
 - Instanced Line Rendering Part II: Alpha blending: Rye Terrell's blog post which inspired me to pare the draw calls down to two and publish this module.
 
© 2021 Ricky Reusser. MIT License.

