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 = baseFilterShader().modify(() => {
    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)
    }
    getColor((inputs, canvasContent) => {
      // Slightly vary the distance per
      // pixel so the result looks dithered
      // and not stepped
      const off =
        rnd(inputs.texCoord * 123.456)
      const toCenter =
        -normalize(inputs.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 =
          (inputs.texCoord - 0.5) *
          sampleScale + 0.5
        const toSample = inputs.texCoord -
          sampleCoord
        const sampleDist = sqrt(
          dot(toSample, toSample)
        )
        const opacity = getTexture(
          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
      return [c, avg]
    })
  })
}
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)
}