Methodology

How the scoring and generation actually work

Everything on this page is a description of code in this repository, not a marketing claim. Where a number is an engineering estimate rather than a measurement, it says so.

Last updated 2026-11-05

What the readability score measures

An emote is scored by downscaling it to 28×28 — the size Twitch chat renders — and then measuring properties of that result. The downscale uses a premultiplied area-average filter. That detail matters: averaging straight RGBA produces dark halos around transparent edges, which would poison the contrast measurements, so colour is premultiplied by alpha before averaging and un-premultiplied afterwards.

The five measurements

  • Silhouette coherence. The opaque mask is split into 4-connected components. One large blob reads; six small ones turn to dust.
  • Visible share. The proportion of the emote clearing a 3:1 WCAG contrast ratio against dark chat (#18181B) and light chat (#F5F5F5).
  • Edge softness. The share of the subject that ends up partially transparent after downscaling, which is what "mushy" actually means numerically.
  • Canvas fill. Subject area as a fraction of the 28×28 canvas.
  • Border bleed. How much of the canvas edge ring is opaque, which predicts clipping.

Why dark chat is weighted higher

Contrast is scored 80% on dark chat and 20% on light chat. Twitch and Discord are predominantly used in dark mode, so an emote that vanishes on dark is broken while one that merely softens on light is a note rather than a failure.

An earlier version weighted the two equally and graded a bright orange emote as a C because it was low-contrast on near-white. That was technically correct and practically wrong: it would have told most users their perfectly good emote had failed. The weighting was changed to match how the artefact is actually viewed.

Hard gates, not just weights

A plain weighted average let a subject filling 14% of the canvas score in the high 70s, because one blob, crisp edges and high contrast are easy for a tiny shape. Some failures are disqualifying rather than tradeable, so they multiply the score instead of nudging it. A 14%-fill speck now scores in the 40s.

What the score is not

It is a legibility measure, not an art-quality measure. A plain flat disc scores 100, which is correct: a plain flat disc is perfectly legible. The score answers "will this read in chat", not "is this good".

Consistency scoring

Each emote in a set is measured on mean ink colour, identity hue (the saturated colour viewers recognise the character by), bounding-box aspect, canvas fill, outline share and readability. The set's median becomes the centre, and each piece is scored on its distance from it.

The thresholds are calibrated against measured noise. During development, two generations of the same prompt with the same reference differed by about 6 ΔRGB mean colour and 7% framing. Anything inside that band is treated as variance rather than drift — otherwise every set would be flagged and the signal would be worthless.

Generation and set consistency

One emote is generated and approved first. That image becomes the locked character reference, and every other reaction is generated from that reference rather than from a fresh roll of the same description. Every prompt carries a constant legibility block: one character, one expression, ~60% canvas fill, thick outline, flat colours, no text, a solid background, designed for 28px.

A controlled experiment compared one reference against two references (the base plus one approved emotion), using the same emotion and prompt in both arms. The two arms came out visually near-identical, with the identity colour differing by 3.7 ΔRGB — inside natural variance. The multi-reference pipeline was not built as a result. That is worth stating plainly: the simpler approach was kept because the more complex one showed no measurable benefit.

Background removal

Image models have no alpha channel, so "transparent background" produces a painted checkerboard. We generate on a flat colour and cut it out with an edge-seeded flood fill: the seed is the canvas border, and only contiguous background-coloured pixels are removed. Interior whites — eye highlights, teeth, a cream belly — are never reached, so they survive. A global colour key cannot do this.

Export

Each platform size is resampled independently from the source with the same premultiplied filter, rather than stepping down through intermediate sizes, which compounds rounding error. Every file is checked against its platform's published byte cap and flagged if it exceeds it. Encoding, resizing and ZIP creation all run in the browser.

What we do not do

  • We do not upload or store images used in the free browser tools.
  • We do not train models on your generated emotes.
  • We do not claim to measure art quality, emotional impact, or whether a platform will approve an upload.
  • We do not publish a Twitch Sub Points-to-emote-slots table, because Twitch does not publish one and the third-party numbers disagree.

Corrections

If a platform changes a specification and this page is out of date, that is a bug. Platform specs were last verified against Twitch, Discord, YouTube and Slack documentation in November 2026.

Check an emote yourself

The scorer is free and runs entirely in your browser.

Open the checker