Glow Text

← All Butter documentation
let font
let txt
let glowColor
let size = 30
let glow
let blurFbo

async function setup() {
  font = await loadFont('').updatesSize()
  txt = createInput('').updatesSize()
  glowColor = createColorPicker()

  textFont(font)
  textSize(size)
  
  createCanvas(
    fontWidth(txt.value()) * 1.75,
    textLeading() *
      txt.value().split('\n').length *
      1.75,
    WEBGL
  )

  blurFbo = createFramebuffer()

  glow = buildFilterShader(() => {
    let c = uniformVec3(() => [
      red(glowColor.value())/255,
      green(glowColor.value())/255,
      blue(glowColor.value())/255,
    ])
    const rnd = (p) => {
      let p3 = fract(p.xyx * .1031)
      p3 += dot(p3, p3.yzx + 33.33)
      return fract((p3.x + p3.y) * p3.z)
    }
    filterColor.begin()
    // Slightly vary the distance per
    // pixel so the result looks dithered
    // and not stepped
    const off =
      rnd(filterColor.texCoord * 123.456)
    const toCenter =
      -normalize(filterColor.texCoord - 0.5)
    const glowScale = 0.1
    let avg = 0
    let total = 0
    for (let i = 0; i < 20; i++) {
      const sampleScale =
        mix(1, (i + off)/20, 0.5)
      const sampleCoord =
        (filterColor.texCoord - 0.5) *
        sampleScale + 0.5
      const toSample = filterColor.texCoord -
        sampleCoord
      const sampleDist = sqrt(
        dot(toSample, toSample)
      )
      const opacity = getTexture(
        filterColor.canvasContent,
        sampleCoord
      ).a
      // Weight the samples higher
      // the closer they are to the
      // current pixel
      const weight =
        pow(1 - sampleDist * 2, 8)
      total += weight
      avg += opacity * weight
    }
    avg /= total + 1e-6
    avg = pow(avg, 0.5) // Boost opacity
    filterColor.set([c, avg])
    filterColor.end()
  })
}
function draw() {
  clear()
  fill(255)
  textAlign(CENTER, CENTER)
  textSize(size)
  textFont(font)
  text(txt.value(), 0, 0)
  filter(glow)

  blurFbo.draw(() => {
    clear()
    text(txt.value(), 0, 0)
    filter(BLUR, 1)
  })
  imageMode(CENTER)
  blendMode(ADD)
  image(blurFbo, 0, 0)
}