First of all, this shader was not designed to create borders, it creates contours and has a convergence point inside a shape, where all gradients meet. It will look like a border if the shape is symmetrical but not in other cases. So for borders you need to come up with a different approach.
The idea here is to provide a shape border as a collection of line segments in the same space as UVs and then colorize the distance from the current uv point (pixel) to the nearest border segment (line). For that the uv origin needs to be inside the shape.
Function pointInTriangle builds a triangle from the beginning and the end of a polygon segment ( a line) and the origin point. Then it checks if the current pixel uv coordinates belong to the triangle, if they do then calculates the distance.
It’s like raycasting from the center of the shape to all border vertices to make triangles and then calculate a distance inside the chosen triangle. The result depends on where the center is and how curvy the shape is. It will not work for any shape.
Lines are made of separate segments, for a triangular shape made out of 3 points [A,B,C], lines need to be in the format [A,B, B,C, C,A].
Making lines out of position array is tricky because there might be vertices in the middle of the shape which are not the part of the shape borderline. Also, shapes might have seams for uv unwrapping, so some vertices will be duplicated. Thus some manual cleanup might be needed.
On top of that you need to know where the center of the uv coordinate system is and make adjustments to uv values and line values to keep them centered, the way I did it for the heart shape.
For shapes uvs are not normalized, they will be vertices world coordinates.
Uv origin depends on how the shape was created, for example for ellipse and heart shape uvs originally will be set like this, so the heart shape needs adjustment:
You can use these two lines to see each of the shapes:
createEllipse(); // ellipse
//createEllipse(hgeom); // heart