Profile picture

GustavBylund

+46 (0)73 026 26 86hello@gustavbylund.semaistho

Make twitch emotes bigger

Which of these emotes would you prefer?

small emote
28x28
medium emote
56x56
large emote
112x112

Emotes are from Linkus7 on Twitch

I think that the 112x112 version is a bit too big, but that the 28x28 version is too small. You can of course use any value inbetween, but it’s probably best to use the images as is, without scaling.

This is a bookmarklet that increases the sizes of all twitch emotes from the standard peasant 28x28px to glorious high definition 56x56px@2x! It does so by using a MutationObserver to listen to every new chat message that is added. MutationObserver is available in all reasonable browsers. Honestly, are you really using IE10?

Bookmarklet

Drag the following link to your bookmark bar!

Big Emotes!

Or add this code to a bookmark:

javascript:!function(e){switch(e){case"small":e=28;break;case"large":e=112;break;default:e=56}e+="px";var t="img.chat-line__message--emote";const r=document.createElement("style"),s=(r.type="text/css",r.innerHTML=t+` { width: ${e} } .chat-image__placeholder .tw-placeholder { width: ${e} !important; height: ${e} !important; }`,document.head.appendChild(r),e=>{var t;e.srcset&&(t=e.srcset.split(/,| /),e.src=t[t.length-2],e.srcset="")});Array.from(document.querySelectorAll(t)).forEach(s);t=document.querySelector("[role='log']");const a=new MutationObserver(e=>{e.forEach(e=>{Array.from(e.addedNodes).forEach(e=>{e.classList.contains("chat-line__message")&&Array.from(e.children).forEach(e=>{setTimeout(()=>{"emote-name"===e.dataset.aTarget&&s(e.firstChild)},50)})})})});window.twitchBiggerEmotesObserver&&window.twitchBiggerEmotesObserver.disconnect(),a.observe(t,{childList:!0}),window.twitchBiggerEmotesObserver=a}("medium");

How it works

It’s a lot longer than some of my other bookmarklets, since it has a bit more configurability.

Every twitch emote has 3 sizes: 1x (28px), 2x (56px) and 4x (112px). Only 1x images are used unless twitch is viewed on a high pixel density display. Since the high res images are available in the srcset, we can get the last image from the srcset and replace our src with that image.

We also need to wait for some time (lovely) since twitch replaces the text with an actual image a bit after adding the chat message to the screen. 1ms was enough most of the time, but 50ms seems to be enough for all images.

;(function(size) {
  switch (size) {
    case 'small':
      size = 28
      break
    case 'large':
      size = 112
      break
    case 'medium':
    default:
      size = 56
      break
  }
  size = `${size}px`

  const selector = 'img.chat-line__message--emote'

  const style = document.createElement('style')
  style.type = 'text/css'
  style.innerHTML = `${selector} { width: ${size} } .chat-image__placeholder .tw-placeholder { width: ${size} !important; height: ${size} !important; }`
  document.head.appendChild(style)

  const makeBigger = image => {
    if (!image.srcset) {
      return
    }
    const srcset = image.srcset.split(/,| /)
    image.src = srcset[srcset.length - 2]
    image.srcset = ''
  }

  Array.from(document.querySelectorAll(selector)).forEach(makeBigger)

  const targetNode = document.querySelector(`[role='log']`)

  const config = {
    childList: true,
  }

  const callback = events => {
    events.forEach(event => {
      Array.from(event.addedNodes).forEach(node => {
        if (!node.classList.contains('chat-line__message')) {
          return
        }
        Array.from(node.children).forEach(childNode => {
          setTimeout(() => {
            if (childNode.dataset['aTarget'] === 'emote-name') {
              makeBigger(childNode.firstChild)
            }
          }, 50)
        })
      })
    })
  }

  const observer = new MutationObserver(callback)

  if (window.twitchBiggerEmotesObserver) {
    window.twitchBiggerEmotesObserver.disconnect()
  }

  observer.observe(targetNode, config)

  window.twitchBiggerEmotesObserver = observer
})('medium')