Skip to content

Add custom emoji spec#586

Open
skizzerz wants to merge 2 commits intoircv3:masterfrom
skizzerz:custom-emoji
Open

Add custom emoji spec#586
skizzerz wants to merge 2 commits intoircv3:masterfrom
skizzerz:custom-emoji

Conversation

@skizzerz
Copy link
Contributor

There's a lot here and is largely guided from some discussions in #ircv3. Given the already-chunky size of the spec, I opted to omit any methods of programmatically managing the linked-to emoji pack JSON documents for clients to build emoji-management UIs (and for servers to maintain stricter control over URLs contained within the emoji packs). I'll be sending that up as a separate spec at some point in the future unless someone else beats me to it first.

Comment on lines +46 to +48
When receiving a PRIVMSG, NOTICE, or [reaction](../client-tags/react.html) with an emoji tag, clients search for all occurrences of the exact substrings of each shortcode and optional suffix surrounded by a colon (`:`) on each side outside of monospaced contexts, and MAY replace those strings with the associated custom emoji image for the provided shortcode from the emoji pack whose id matches pack-id. Whether any particular shortcode is replaced with an associated custom emoji is an implementation decision for the client (see Client implementation considerations below).

A monospaced context is a portion of the message body beginning with the monospace formatting code 0x11 and ending with either the monospace formatting code 0x11 again or the format reset code 0x0F. Even if a client does not support 0x11 for formatting text as monospaced, it MUST NOT replace custom emoji shortcodes within such contexts with the associated images. This allows for an easy way of "escaping" emoji shortcodes that would otherwise be replaced by images.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can clients escape outside of monospace blocks or on channels that strip formatting codes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this monospace formatting code usage at all. Could we instead have the client send a number with the emoji tag saying "replace this numbered occurence with the emoji".

So you could send hi there. don't replace this -> :lol: but do replace this -> :lol: with a tag like +draft/emoji=lol=server=2 (or something nicer).

Still possibly vulnerable to server rewriting of messages, but not as brittle as string indices. Pretty sure anything could be vulnerable to server rewriting unless the server gets involved in the tag too tbh.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/2/1 if 0-indexed. What do most regex engines that have occurence targeting use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outside of monospace is what the suffix is for, a client could transform one of those to :lol~###: (where ### is some 1-3 digit number) and specify that as the emoji, while leaving :lol: as a non-emoji (not defined in the client tag). I could get rid of monospace thing entirely and rely only on suffixing.

Regex is 1-indexed for capture groups (0 is the entire matched string)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not capture groups though, just nth occurence. But I think sed's s/foo/bar/2 is 1-indexed too. Don't think it's a common feature in other languages though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the shortcode has to be ASCII a client could just escape stuff using a zero-width space.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't copy-pasting the message from a receiving client preserve the zero-width space? This would be inconvenient (eg. if it's code, compilers would return a syntax error)

Copy link
Contributor Author

@skizzerz skizzerz Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned using \:lol: to escape in #ircv3, what about that?

I don't particularly care what escaping mechanism we end up going with, or if we allow escaping at all (the suffix solution in my draft spec would allow us to avoid specifying any escaping mechanism). If we go with the backslash thing then clients which don't support that particular emoji will still see and render the literal backslash, which could be a bit ugly.

It sounds like the monospace idea is probably not the right path forward so my next update will remove that paragraph. What remains (shortcode+suffix) can then be subject to a dumb string search operation without any additional considerations needed by the client, which can possibly simplify implementation.

Given the shortcode has to be ASCII a client could just escape stuff using a zero-width space.

I was originally planning on allowing UTF8 text for shortcodes but ran into issues around coming up with a concise enough character set that could be replaced without issues (as a short example, if bidi override marks were allowed in shortcodes and then that got replaced, how the rest of the message is displayed would perhaps not be consistent between clients). Clients would likely also need to normalize both the message and tag because there's multiple ways to write the exact same sequence of visible characters in Unicode.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't actually see anywhere in this spec that explains what the suffix is for, as defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suffix was dropped in the latest draft (as was the client tag in its entirety). I didn't add any escaping mechanism into the draft because it wasn't clear to me which escaping mechanism (if any) would be the best one to use. Would like to see some consensus on that if possible.


Clients should implement defensive coding practices around image parsing, as there is a chance image data is malicious. This is especially relevant for SVG support as SVG natively supports scripting capabilities that could run client-side and could contain external XML entities causing additional web traffic or broken parsing, but security vulnerabilities do exist with image processing libraries in general. Clients should be strict in what they accept and reject any malformed image data.

If a client is unwilling or unable to render any particular emoji image, they have a choice of displaying the alt text or leaving the shortcode as-is in the message body. In general, leaving the shortcode as-is is likely the best choice, as it doesn't potentially introduce arbitrarily-long content that users on other clients are unlikely to see. The alt text could still be exposed as a tooltip when hovering over the shortcode, for example.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is inconsistent with the definition of "alt" above. Considering each case in the "alt Decision Tree":

  • If the image contains text
    • … and the text is also present as real text nearby: then replacing the shortcode with the (empty) alt is the right decision
    • … and the text is only shown for visual effects: then replacing the shortcode with the (empty) alt is also the right decision
    • … and the text has a specific function, for example is an icon: then it depends
    • … and the text in the image is not present otherwise: then replacing the shortcode with the alt is the right decision
  • The image used in a link or a button: not applicable
  • The image contributes meaning to the current page or context
    • … and it’s a simple graphic or photograph: then it depends
    • … and it’s a graph or complex piece of information: not applicable
    • … and it shows content that is redundant to real text nearby: then replacing the shortcode with the (empty) alt is also the right decision
  • The image purely decorative or not intended for users: then replacing the shortcode with the (empty) alt is also the right decision

so in some cases replacing with the alt is better, and there is no case where keeping the shortcode is unambiguously better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've revised this text to provide better clarification. The alt decision tree was also moved to a section about authoring emoji pack documents, since it provides guidance on the creation of alt attributes rather than the usage of them.


## Emoji images

Emoji images SHOULD be a minimum of 128x128 pixels in size for raster images. This allows clients to size emoji appropriately in their UI without needing to worry about blurry images on high DPI displays. This specification does not dictate any particular file formats for emoji images, however clients SHOULD support static PNG and JPG images and MAY support any number of additional formats. See the client implementation considerations section for discussion on the security implications of supporting certain formats.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allowing smaller images can be useful for pixel art style icons that would lose detail when downsampled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec already allows this (SHOULD is not MUST). Do you think there needs to be a mention in the considerations section as to when smaller images are appropriate, or is it good as-is?

This updated draft incorporates the following changes:

- Removal of the +draft/emoji client tag. Correctly defining this tag
  would result in additional work in the client, and it renders
  copy/paste workflows more difficult as any clipboard operations would
  need to also include tag metadata instead of just textual content.
- Removal of the suffix notation. With the removal of the client tag
  this notation no longer performs any useful function, and was
  confusing with regards to what it accomplished in any event.
- Disambiguation of pack-id built into emoji syntax. With the removal of
  the client tag, pack disambiguation for duplicative shortcodes needs
  to happen inside the message content. An algorithm to resolve a
  shortcode to a pack id in the event one is not explicitly specified
  was also added to ensure clients agree on the same emoji object for
  such cases.
- Shortcodes and pack-ids expanded to allow (almost) all Unicode
  characters. To make parsing easier, / is not allowed in shortcodes and
  : is not allowed in both shortcodes and pack ids. Other forbidden
  characters include whitespace, control, and text fomatting codes as
  allowing these could result in portions of a message outside of the
  emoji-value rendering differently depending on whether or not the
  shortcode was replaced.
- The alt text guide was moved to a new pack author considerations
  section since it provides guidance on the creation of alt attributes
  rather than the usage of them.
- Language allowing channel emoji packs to be shared between channels
  was added.
- Guidance regarding multiline messages with multiline-concat was added
  to the client considerations section.

Notably, an escaping mechanism was NOT added in this draft. It is likely
to be added in a future draft, but there isn't clear consensus on what
that mechanism should look like as of yet.

1. If the message is in a channel, look up the shortcode within the emoji pack document specified by that channel's `draft/emoji` METADATA.
2. If step 1 fails to produce a shortcode mapping, look up the shortcode within the emoji pack document specified by ISUPPORT `draft/EMOJI`.
3. If steps 1 and 2 fail to produce a shortcode mapping, an implementation MAY attempt to resolve the pack-id via other means (such as a local cache of known packs).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of this fallback?

To me it sounds like an interoperability issue, where different IRC clients could resolve emojis in different ways.

The specification provides an example of replacing :wave: with 👋, but I don't understand why couldn't the client simply replace :wave: with 👋 when sending the message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client could certainly do that. I'm not going to mandate that clients do so in outgoing messages because it's impossible to specify in any clean fashion and there's no feature negotiation needed to make use of custom emoji.

The reason for the fallback is simple: I cannot predict where custom emoji may go in the future or what inventive things users and clients may eventually do with it, and the algorithm to resolve an emoji shortcode is a MUST with a strictly-defined ordering. This fallback offers an escape hatch to augment the resolution algorithm in the future, such as via a future specification which brings some additional optional features into custom emoji. These extensions would not be possible without this fallback without errata to this specification as well (breaking the ability for those extensions to be self-contained).


## Emoji images

Emoji images SHOULD be a minimum of 128x128 pixels in size for raster images. This allows clients to size emoji appropriately in their UI without needing to worry about blurry images on high DPI displays. This specification does not dictate any particular file formats for emoji images, however clients SHOULD support static PNG and JPG images and MAY support any number of additional formats. See the client implementation considerations section for discussion on the security implications of supporting certain formats.
Copy link

@sugar700 sugar700 Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may make sense to recommend IRC clients to send HTTP Accept header with the list of formats they support when they send a request to retrieve emoji. This would allow IRC servers to, say, determine whether to send animated WebP file or a PNG emoji, depending on file format support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants