Edit in JSFiddle

const gpu = new GPU();
const image = document.getElementById('img');

function lum(r, g, b) {
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
gpu.addFunction(lum);

function verticalLine(x) {
  return x;
}
gpu.addFunction(verticalLine);

function diagonalLine(x, y) {
  return x + y;
}
gpu.addFunction(diagonalLine);

function reverseDiagonalLine(x, y) {
  return y - x;
}
gpu.addFunction(reverseDiagonalLine);

function circleLine(x, y) {
  return Math.round(Math.sqrt(x * x + y * y));
}
gpu.addFunction(circleLine);

function waveLine(x, y) {
  return Math.round(y / this.constants.k * Math.cos(x / this.constants.k));
}
gpu.addFunction(waveLine);

function shade(img) {
  // Get position
  const x = this.thread.x;
  const y = this.thread.y;

  // Get pixel
  const p = img[y][x];

  // Get luminace
  const l = lum(p[0], p[1], p[2])

  // Threshold color
  const space = l * this.constants.spaces;

  // Exponentially space out lines
  const lineSpacing = Math.round(Math.pow(space, this.constants.exp));

  // Default color
  this.color(1, 1, 1);

  // Apply function
  let f = 1;
  if (this.constants.func === 1) {
    f = verticalLine(x);
  } else if (this.constants.func === 2) {
    f = diagonalLine(x, y);
  } else if (this.constants.func === 3) {
    f = circleLine(x, y);
  } else {
    f = waveLine(x, y);
  }

  if (f % lineSpacing === 0) {
    this.color(0, 0, 0);
  }
}

let first = true;

function update() {
  const render = gpu.createKernel(shade)
    .setGraphical(true)
    .setOutput([image.width, image.height])
    .setConstants({
      spaces: parseInt(document.getElementById('spaces').value),
      exp: parseFloat(document.getElementById('exp').value),
      k: parseFloat(document.getElementById('k').value),
      func: parseFloat(document.getElementById('function').value),
    })
  document.getElementById('spaces-value').innerHTML = document.getElementById('spaces').value
  document.getElementById('exp-value').innerHTML = document.getElementById('exp').value
  document.getElementById('k-value').innerHTML = document.getElementById('k').value
  render(image)
  if (first) {
    const canvas = render.getCanvas();
    document.getElementsByClassName('images')[0].appendChild(canvas);
    first = false;
  }
}

document.getElementById('exp').oninput = () => {
  update();
}

document.getElementById('spaces').oninput = () => {
  update();
}

document.getElementById('k').oninput = () => {
  update();
}

document.getElementById('function').onchange = () => {
  update();
}

document.getElementById('pic').onchange = function(evt) {
  var tgt = evt.target || window.event.srcElement,
    files = tgt.files;

  // FileReader support
  if (FileReader && files && files.length) {
    var fr = new FileReader();
    fr.onload = function() {
      document.getElementById('img').src = fr.result;
      setTimeout(update, 0);
    }
    fr.readAsDataURL(files[0]);
  }

  // Not supported
  else {
    // fallback -- perhaps submit the input to an iframe and temporarily store
    // them on the server until the user's session ends.
  }
}

update();