diff --git a/public/javascripts/vector-render.js b/public/javascripts/vector-render.js
index 4d4bc9f8e247e8c5c36e71bcf7cc5d866c09235a..add2a7bec17b3e1759e770a94e571a1c5af47719 100644
--- a/public/javascripts/vector-render.js
+++ b/public/javascripts/vector-render.js
@@ -121,33 +121,100 @@ function render_vector_drawing(a, padding) {
 }
 
 
-function render_vector_star(edges,xradius,yradius,offset) {
+function render_vector_star(tips,width,height,stroke) {
+  //A 5-pointed (5 tips) regular star of radius from center to tip of 1 has a box around it of width = 2 cos(pi/10) and height = 1 + cos(pi/5)
+  //  assuming the star is oriented with one point directly above the center.
+  //  So the center of the star is at width * 1/2 and height * 0.552786 which is 1 / (1 + cos(pi/5)) (also assuming the y-axis is inverted).
+  //  The inner points are at radius 0.381966 = sin(pi/10)/cos(pi/5).
+  //  Fortunately with simple transformations with matrices, we can do rotations and scales easily.
+  //  See https://en.wikipedia.org/wiki/Rotation_matrix for details.
+  //  But because the stroke is done after scaling (it's not scaled), we have to adjust the points after the rotation and scaling happens.
+  //A 10-pointed regular star is simpler because it is vertically symmetrical.
+
+  //NOTE: for very thick stroke widths, and small stars, the star might render very strangely!
+
+  var xcenter = width/2;
+  var ycenter = 0;
+  var inner_radius = 0;
+  if (tips == 5) {
+    ycenter = height * 0.552786;
+    inner_radius = 0.381966; //scale compared to outer_radius of 1.0
+  } else {
+    //tips == 10
+    ycenter = height/2;
+    inner_radius = 0.7; //scale compared to outer_radius of 1.0
+  }
 
-  edges *= 2;
+  // Coordinates of the first tip, and the first inner corner
+  var xtip = 1; // radius 1
+  var ytip = 0;
+  var xinner = inner_radius * Math.cos(Math.PI/(tips==5?5:10));
+  var yinner = inner_radius * Math.sin(Math.PI/(tips==5?5:10));
 
   var points = [];
-  var degrees = 360 / edges;
-  for (var i=0; i < edges; i++) {
-    var a = i * degrees - 90;
-    var xr = xradius;
-    var yr = yradius;
 
-    if (i%2) {
-      if (edges==20) {
-        xr/=1.5;
-        yr/=1.5;
-      } else {
-        xr/=2.8;
-        yr/=2.8;
-      }
-    }
+//  var tmp_outside_points = []; // uncomment to see the calculated edge of the star (outside the stroke width)
+
+  var angle = 2*Math.PI / tips;
+  // generate points without offset from stroke width first
+  for (var i=0; i < tips; i++) {
+    var a = i * angle - Math.PI/2;
+
+    // Tip first...
+    // Rotate the outer tip around the origin:
+    var x = xtip * Math.cos(a);  // because ytip = 0 we don't include:  - ytip * Math.sin(a);
+    var y = xtip * Math.sin(a);  // because ytip = 0 we don't include:  + ytip * Math.cos(a);
+    // Scale for the bounding box:
+    x = x * width / (2 * Math.cos(Math.PI/10));
+    y = y * height / (tips==5?(1 + Math.cos(Math.PI/5)):2);
+    points.push([x,y]);
+//    tmp_outside_points.push(x+" "+y); // uncomment to see the calculated edge of the star (outside the stroke width)
+
+    // Now the inner corner...
+    // Rotate the inner corner around the origin:
+    x = xinner * Math.cos(a) - yinner * Math.sin(a);
+    y = xinner * Math.sin(a) + yinner * Math.cos(a);
+    // Scale for the bounding box:
+    x = x * width / (2 * Math.cos(Math.PI/10));
+    y = y * height / (tips==5?(1 + Math.cos(Math.PI/5)):2);
+    points.push([x,y]);
+//    tmp_outside_points.push(x+" "+y); // uncomment to see the calculated edge of the star (outside the stroke width)
+  }
 
-    var x = offset + xradius + xr * Math.cos(a * Math.PI / 180);
-    var y = offset + yradius + yr * Math.sin(a * Math.PI / 180);
-    points.push(x+","+y);
+  var inset_points = [];
+  for (var i=0; i < points.length; i++) {
+    var pA = points[(((i-1)%points.length)+points.length)%points.length]; // Javascript modulus "bug"
+    var p0 = points[i];
+    var pB = points[(i+1)%points.length];
+
+    var dAx = p0[0] - pA[0];
+    var dAy = p0[1] - pA[1];
+    var dBx = p0[0] - pB[0];
+    var dBy = p0[1] - pB[1];
+
+    var dBLength = Math.sqrt(dBx**2 + dBy**2);
+
+    // The trig here is a bit hairy.  Basically, finding the inset points is done by finding the angle (theta)
+    // between the tips and the neighboring inner corners (or vice versa).  Then, that angle is used to
+    // calculate vector scaling factors for half the thickness of the stroked path.  Which then is used to find
+    // the actual inset points for the tips and inner corners.
+    var theta = Math.atan2(dAx*dBy-dAy*dBx, dAx*dBx + dAy*dBy); // angle between the vectors
+    var theta = (i%2? Math.PI * 2 - theta : theta);
+    var stroke_prime = dBLength * Math.tan(theta/2); // this is really a scaling factor
+    var xprime = p0[0] + (i%2?-1:1)*((stroke/2)/stroke_prime)*dBx + dBy*(stroke/2)/dBLength;
+    var yprime = p0[1] + (i%2?-1:1)*((stroke/2)/stroke_prime)*dBy + -1 *  dBx*(stroke/2)/dBLength;;
+
+    inset_points.push(xprime+","+yprime);
   }
-  
-  return "<polygon points='"+points.join(" ")+"'/>";
+
+// NOTE: use svg transformations to center the thing
+  return "<polygon stroke-miterlimit='64' points='"+inset_points.join(" ")+"' transform='translate(" + xcenter + " " + ycenter + ")'/>";
+
+// Append these if you want to see what is being calculated.
+// The cyan dashed line is the outside of the star including the stroke width.
+// The red dashed line is just the star polygon points themselves.
+//    "<polygon stroke-width='4' stroke='red' stroke-dasharray='16 12' fill-opacity='0' points='"+inset_points.join(" ")+"' transform='translate(" + xcenter + " " + ycenter + ")'/>" +
+//    "<polygon stroke-width='4' stroke='cyan' stroke-dasharray='16 12' fill-opacity='0' points='"+tmp_outside_points.join(" ")+"' transform='translate(" + xcenter + " " + ycenter + ")'/>";
 }
 
 function transform_vector_template(cmds, xr, yr, offset) {
@@ -251,8 +318,8 @@ function render_vector_shape(a) {
     diamond: function()   { return render_vector_ngon(4, xr, yr, offset); },
     square: function()   { return "" },
     triangle: function() { return render_vector_ngon(3, xr, yr, offset); },
-    star: function() { return render_vector_star(5, xr, yr, offset); },
-    burst: function() { return render_vector_star(10, xr, yr, offset); },
+    star: function() { return render_vector_star(5, a.w, a.h, a.stroke); },
+    burst: function() { return render_vector_star(10, a.w, a.h, a.stroke); },
     speechbubble: function() { return render_vector_speechbubble(xr, yr, offset); },
     heart: function() { return render_vector_heart(xr, yr, offset); },
     cloud: function() { return render_vector_cloud(xr, yr, offset); },