I want to generate a sunburst to use with a laser-cutting service, like below:

This has a couple of important features:
- It’s a single path, for the laser to use
- The rays on the sun can intersect a bounding box, including the corners
- This will produce two interlocking parts (e.g. for printmaking, these can be inked separately, and combined)
The code is below – this works with Paper.js:
var postyle = { fillColor:'grey', strokeColor: 'black'}
const size = 200;
const rect = [0, 0, [ size, size]];
const ratio = 0.25;
const radius = size * ratio;
const spokes = 48;
const pi = 3.14;
const center = [0, 0]
var path = new paper.Path();
path.strokeColor = "#000";
path.closed = true;
function ip(a) {
return [
radius * Math.cos(a),
radius * Math.sin(a)
];
}
function intersect(x1, y1, x2, y2, mixX, minY, maxX, maxY) {
var point = rectangleIntersect(maxX - x1, maxY - y1, x2 - x1, y2 - y1);
return point && { x: point.x + x1, y: point.y + y1 };
}
function rectangleIntersect(w, h, x, y) {
var sx = x > 0 ? 1 : -1;
var sy = y > 0 ? 1 : -1;
x *= sx;
y *= sy;
if (x < w && y < h) return null;
var m = x * h;
var n = y * w;
if (m < n) w = m / y;
if (m > n) h = n / x;
return [ Math.round( sx * w ), Math.round(sy * h ) ];
}
function outer(a) {
return rectangleIntersect(
size,
size,
100000 * Math.cos(a) + size/2,
100000 * Math.sin(a) + size/2,
);
}
function maybeCorner(p1, p2, a1) {
const corners = [
[1 * size, -1 * size],
[1 * size, 1 * size],
[-1 * size, 1 * size],
[-1 * size, -1 * size],
];
if (p1[0] != p2[0] &&
p1[1] != p2[1]) {
const idx = Math.round(2*a1/pi) % 4;
return corners[idx];
}
}
for (let i = 0; i < spokes; i++) {
const a1 = pi / spokes * (2 * i);
const a2 = pi / spokes * (2 * i + 1);
const inner1 = ip(a1);
const inner2 = ip(a2);
const outer1 = outer(a1);
const outer2 = outer(a2);
const points = [
inner1,
outer1,
maybeCorner(outer1, outer2, a1),
outer2,
inner2].filter(
(p) => !!p
);
points.map(
([x, y]) => {
path.add(new paper.Point(x + center[0], y + center[1]));
});
}