     else
       msg
 
-  # Produce a text bubble that contains `msg` printed in the
-  # font `font` in the size `size`. The bubble will be at most
-  # `max` pixels wide, and will be padded according to `AYP_TEXT_PADDING`
-  #
-  # The return value will be a GD image.
-  textBubble: (msg, font=FONT_PATH, size=AYP_FONT_SIZE, max=AYP_BUBBLE_MAX_WIDTH) =>
-    msg = @formatForTextBubble(msg, font, size, max)
-    [w, h] = @textSize(msg, font, size)
-
-    frame = GD.createTrueColor(
-      w + (AYP_TEXT_PADDING * 2),
-      h + (AYP_TEXT_PADDING * 2)
-    )
-    frame.saveAlpha(1)
-    white = frame.colorAllocate(0xff, 0xff, 0xff)
-    black = frame.colorAllocate(0x00, 0x00, 0x00)
-    frame.fill(0, 0, white)
-
-    frame.stringFT(black, font, size,
-      0,                           # Rotation angle
-      AYP_TEXT_PADDING,            # x
-      AYP_TEXT_PADDING + size + 1, # y
-      msg
-    )
-    return frame
-
-  # Composite `sprite` onto `dst` in full.
+    # Composite `sprite` onto `dst` in full.
   # Offsets `sprite` `+left` from the left
   # and `+top` from the top
   compositeImage: (dst, sprite, left, top) ->

    @buildPanel @script[2..3], (err, panel) -> finishPanel(err, 1, panel)
    @buildPanel @script[4..5], (err, panel) -> finishPanel(err, 2, panel)

  # Load avatars for `names` and invoke `cb` as:
  # `cb(err, {"Nickname": avatarImg, ...})`
  # mapping each name to an avatar image that
  # can be used to represent it.
  #
  # `err` is only set on failure
  loadAvatars: (names, cb) =>
    # Prepare requirements
    names = names.map (n) -> {name: n, img: null, err: null}
    failed = false

    fail = (err) ->
      cb(err, null)
      return faliled = true

    charPathForNick = (nick) ->
      potential = path.resolve(AVATAR_BASE, "#{nick.toLowerCase()}.png")
      return potential if (try fs.statSync(potential))
      return path.resolve(AVATAR_BASE, "default.png")

    for nameObj in names
      do (nameObj) ->
        GD.openPng charPathForNick(nameObj.name), (err, img) ->
          return if failed
          return fail(err) if err
          nameObj.img = img unless err

          # Are we done? Then build up a dictionary
          # and tell the caller.
          if names.every((o) -> o.img)
            avatars = {}
            for obj in names
              avatars[obj.name] = obj.img
            cb(null, avatars)

  # Draw the text into a `frame` described by
  # the `@script`

              return msg.reply "Woooops! Failed to upload: #{err}" if err
              msg.reply "I made a thing: http://s3.amazonaws.com/#{AYP_AWS_BUCKET}/#{name}"

# This wraps up everything that builds the image strips of the comic
#
# Usage:
# `new AYPStrip script, (err, image) -> ...`
# Will invoke the callback with the completed
# strip when it's ready.
class AYPStrip
  # Constructor just stores the script and callback
  # and passes flow to the builder.
  constructor: (@script, @ready) ->
    do @buildComic

