The Sea

Repeated print of fan motif with subtle variations in curve and placement.

Loading...
import badge from "/scratchpad/_lib/badge.asset.mjs"
import frame from "/scratchpad/_lib/frame.asset.mjs"
import posterize from "/scratchpad/posterize/posterize.asset.mjs"
import sequence from "/scratchpad/_lib/sequence.asset.mjs"
import palette from "/scratchpad/_lib/palette.asset.mjs"
import * as random from "/scratchpad/_lib/random.asset.mjs"

export default (canvas) => {
  const scale = window.devicePixelRatio || 1
  canvas.width = canvas.offsetWidth * scale
  canvas.height = canvas.offsetHeight * scale

  const ctx = canvas.getContext("2d")
  const inner = Math.min(canvas.width, canvas.height)
  const outer = inner / 12

  ctx.fillStyle = palette.canvas
  ctx.fillRect(0, 0, canvas.width, canvas.height)

  return sequence([
    () => arcs(ctx, outer),
    () => frame(ctx, 20 * scale),
    () =>
      posterize({
        ctx,
        radius: 1,
        iterations: 3,
        ramp: 4.2,
        overshoot: 0.6,
      }),
    () => badge(ctx),
  ])
}

const arcs = function (ctx, outer) {
  const inner = 1
  const rings = 12

  ctx.fillStyle = palette.canvas
  ctx.strokeStyle = palette.dark

  let y = 0
  let x = 0
  let row = 0
  let rWidth = random.wobble(outer, outer / 2)
  let w = outer * 0.1
  let lw = w / 4.5
  let width, height

  while (y < ctx.canvas.height + rWidth) {
    y = row * (rWidth * 0.5)
    x = random.wobble(-rWidth * (row % 2), rWidth * 0.25)
    row++

    while (x < ctx.canvas.width + rWidth) {
      width = random.wobble(rWidth, w / 2)
      height = random.wobble(rWidth, w)

      for (let i = 0; i < rings; i++) {
        for (let repeat = 0; repeat <= 2; repeat = ++repeat) {
          ctx.lineWidth = random.wobble(lw, lw * 0.5)

          const radius = height - (height - inner) * (i / rings)
          const wf = w / 3
          const cw = width - (width - inner) * (i / rings)
          const cr = random.wobble(radius, w / 6)
          const cx = random.wobble(x, wf)
          const cy = random.wobble(y, wf)
          const top = random.wobble(cy - cr * 1.1, wf)

          ctx.beginPath()
          ctx.moveTo(cx - cw, cy)
          ctx.bezierCurveTo(
            random.wobble(cx - cw, wf),
            random.wobble(cy - cr * 0.4, wf),
            random.wobble(cx - cw * 0.66, wf),
            top,
            cx,
            top
          )
          ctx.bezierCurveTo(
            random.wobble(cx + cw * 0.66, wf),
            top,
            random.wobble(cx + cw, wf),
            random.wobble(cy - cr * 0.4, wf),
            random.wobble(cx + cw, wf),
            cy
          )

          ctx.stroke()

          if (repeat === 0) {
            ctx.fill()
          }

          if (random.maybe(0.018)) {
            ctx.fillStyle = random.maybe() ? palette.dark : palette.canvas
            ctx.fill()
          } else {
            ctx.fillStyle = palette.canvas
          }
        }
      }
      x += random.wobble(width * 2, w)
    }
  }

  return ctx
}