lsh-LineWalk


As I worked on these, I began to think of them as pinwheels. Getting the right “flutter” out was a challenge, and I also had a bug for a little where content ended up mostly off the page. I ended up trying to “weave” in the iteration by flipping whether I add or subtract it in the simplex noise for the x or y.

const Simplex = require("https://unpkg.com/simplex-noise@2.4.0/simplex-noise.js");
const simplex = new Simplex();
const width = 761;
const height = width;
// source: https://rosettacode.org/wiki/Map_range#ES6
const rangeMap = (a, b) => (s) => {
  const [a1, a2] = a;
  const [b1, b2] = b;
  // Scaling up an order, and then down, to bypass a potential,
  // precision issue with negative numbers.
  return ((((b2 - b1) * (s - a1)) / (a2 - a1)) * 10 + 10 * b1) / 10;
}

function generatePaths() {
  const start = [Math.random() * width, Math.random() * height];
  const step = 200.0;
  const path = [start];
  for (let i = 0; i < 100; i++) {
    const [px, py] = path.at(-1);
    const theta = simplex.noise2D(px * px * 10 * +i * i, py * py * 10 - i * i);
    const t = rangeMap([-1, 1], [-Math.PI, Math.PI])(theta);
    const x =
      Math.cos(t) * step + simplex.noise2D(px + i, py - i) * 100 + width / 2;
    const y =
      Math.sin(t) * step + simplex.noise2D(px - i, py + i) * 100 + height / 2;
    path.push([x, y]);
  }
  return path;
}

function draw() {
  const svg = d3.create("svg").attr("width", width).attr("height", height);
  svg
    .append("path")
    .attr("d", d3.line()(generatePaths()))
    .attr("fill", "none")
    .attr("stroke", "black");
  return svg.node();
}

lsh-MolnarRecode

1. Some of the lines are orthogonal to each other.
2. Some of the lines make a triangle filling half of the cell.
3. Some lines seem to be darker than the others.
4. Some of the patterns seem to have the same “scale” but less distance between lines.
5. There seems to be multiple scales of grids interacting.
6. Some cells overlap creating a cross hatch.
7. Some angles made a “wide” diamond, while others make a “tall” diamond.
8. Several of the interactions near the center almost form a curve.
9. The largest shape seems to be “16” small blocks (4 big blocks) in the top left corner.
10. It “feels” like there is more void than line.


I think I spent too much time working at a small scale in this work. In the end I don’t feel like I captured the general feel because I focused on little segments. I also spent a lot of time fighting with texturesjs, which was probably time I should have spent in a tool with which I was more familiar. Overall this drawing feels too heavy and I don’t think I captured the angles or interactions all that well.

const width = 761;
const height = width;

function generateRandomNumbers({ num_squares, N }) {
  const m = new Map();
  const out = [];
  while (out.length  d[0]))
  .range([0, width]);
const sy = d3
  .scaleBand()
  .domain(idx.map((d) => d[1]))
  .range([height, 0]);

const t1 = textures.lines().size(5).strokeWidth(1).orientation("2/8");
const t2 = textures.lines().size(5).strokeWidth(1).orientation("6/8");
const t3 = textures.lines().size(25).strokeWidth(1).orientation("7/8");
const t4 = textures.lines().size(25).strokeWidth(1).orientation("1/8");
const t5 = textures.lines().size(50).strokeWidth(1).orientation("5/8");
const t6 = textures.lines().size(50).strokeWidth(1).orientation("3/8");


function generate() {
  const svg = d3.create("svg").attr("width", width).attr("height", height);
  [t1, t2, t3, t4, t5, t6].forEach((t) => svg.call(t));

  svg.select(`pattern#${t4.id()}`).attr("patternTransform", "translate(3)");

  svg
    .selectAll(".rect38")
    .data(generateRandomNumbers({ num_squares, N: 500 }))
    .join("rect")
    .attr("fill", t1.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect78")
    .data(generateRandomNumbers({ num_squares, N: 500 }))
    .join("rect")
    .attr("fill", t2.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect2x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t3.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect22x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t4.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect4x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t5.url())
    .attr("x", ([x, _]) => sx(x) * 2)
    .attr("y", ([_, y]) => sy(y) * 2)
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect4x2")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t6.url())
    .attr("x", ([x, _]) => sx(x) * 2)
    .attr("y", ([_, y]) => sy(y) * 2)
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  return svg.node();
}

generate();

lsh-PlotterTwitter

#PlotterTwitter was better than I expected! Generative art can quickly give rise to an abundance of oatmeal, which is why I was pleasantly surprised at the variety of content I saw. I noticed many artists opted for either multi colored abstract forms or monochromatic pieces that were relatively more representational.

I was particularly fond of Frederik Vanhoutte (@wblut)’s Iso22 piece. The use of void space in the upper segments brings a nice contrast with the detail of the lower segments.