Seed Head

to generate a new and unique variation

Source Code

Every variart piece is a small program. This is the one that drew what you're looking at.

var background = '#3A3244';
var thread = '#F3EEE6';
var margin = 50;
var dot = 6;

var rays = intVariable('Rays', 30, 90);
var droop = intVariable('Droop', 0, 40);

s.rect(0, 0, width, height).attr({fill: background});

// The hub sits somewhere beyond one of the edges, so only its threads reach
// the canvas.
var side = getRandomInt(0, 3);
var along = getRandomInt(0, width);
var away = getRandomInt(20, 80);
var hubX = [along, width + away, along, -away][side];
var hubY = [-away, along, height + away, along][side];
var inner = margin + dot;
var outer = width - margin - dot;

// Where a ray enters and leaves the face; its bead must land in between.
function span(angle){
  var dx = Math.cos(angle), dy = Math.sin(angle);
  var x0 = (inner - hubX) / dx, x1 = (outer - hubX) / dx;
  var y0 = (inner - hubY) / dy, y1 = (outer - hubY) / dy;
  return [Math.max(Math.min(x0, x1), Math.min(y0, y1)),
          Math.min(Math.max(x0, x1), Math.max(y0, y1))];
}

// Aim only at angles that cross the face: the spread of its four corners as
// seen from the hub, measured around the direction of its centre.
var centre = Math.atan2(height / 2 - hubY, width / 2 - hubX);
var first = 0, last = 0;
[[inner, inner], [outer, inner], [inner, outer], [outer, outer]].forEach(function(p){
  var a = Math.atan2(p[1] - hubY, p[0] - hubX) - centre;
  a = Math.atan2(Math.sin(a), Math.cos(a));
  first = Math.min(first, a);
  last = Math.max(last, a);
});
// Rays at the very ends only clip a corner of the face and pile their beads
// there, so trim them.
var trim = (last - first) * 0.1;
first += centre + trim;
last += centre - trim;

for (var i = 0; i < rays; i++){
  var angle = getRandomArbitary(first, last);
  var range = span(angle);
  if (range[1] <= range[0]) { continue; }
  var length = range[0] + (range[1] - range[0]) * getRandomArbitary(0.3, 1);
  var ex = hubX + Math.cos(angle) * length;
  var ey = hubY + Math.sin(angle) * length;

  // Threads sag under their own weight, more the longer and flatter they run.
  var sag = droop / 100 * length * Math.abs(Math.cos(angle)) * 0.6;
  var cx = hubX + Math.cos(angle) * length * 0.55;
  var cy = hubY + Math.sin(angle) * length * 0.55 + sag;

  s.path('M' + hubX + ',' + hubY + ' Q' + cx + ',' + cy + ' ' + ex + ',' + ey)
    .attr({fill: 'none', stroke: thread, strokeWidth: 1.5, strokeOpacity: 0.55, strokeLinecap: 'round'});
  s.circle(ex, ey, dot).attr({fill: thread});
}