5c40e27fde
Wire-protocol specs for nostrnests-style audio rooms, in the style of Nostr NIPs and Blossom BUDs. Each spec documents one self-contained capability that a client or relay can implement; two compliant peers implementing the same set of EGGs round-trip without further coordination. Layout: README.md cover, status table, conformance levels EGG-01.md Room event (kind:30312) required EGG-02.md Auth + WebTransport handshake required EGG-03.md Audio plane (moq-lite) required EGG-04.md Presence (kind:10312) required EGG-05.md In-room chat (kind:1311) optional EGG-06.md Reactions (kind:7) optional EGG-07.md Roles & moderation (kind:4312) optional EGG-08.md Scheduling (status=planned) optional EGG-09.md User server list (kind:10112) optional EGG-10.md Theming (c/f/bg tags) decorative EGG-11.md Recording decorative EGG-12.md Catalog track (catalog.json) optional Conformance levels (Listener / Speaker / Host) defined in the README so a deployment can declare "we implement EGG-01..EGG-04" and other peers know exactly what to expect. Each spec follows the same shape (Summary / Wire format / Behavior numbered MUST/SHOULD/MAY rules / Example / Compatibility) and fits on a single printed page. Wire formats are documented exactly as nostrnests + amethyst implement them on this branch — no hypothetical capabilities, no "future" tags without an EGG number.
105 lines
3.1 KiB
Markdown
105 lines
3.1 KiB
Markdown
# EGG-06: Reactions (`kind:7`)
|
|
|
|
`status: draft`
|
|
`requires: EGG-01`
|
|
`category: optional`
|
|
|
|
## Summary
|
|
|
|
Audience-side ephemeral feedback (👏 ❤️ 🎉 ...) is carried on standard
|
|
NIP-25 `kind:7` reaction events, scoped to the room via an `a`-tag.
|
|
Clients render these as a short-lived floating overlay over the
|
|
participant grid.
|
|
|
|
A reaction is NOT durable state. Clients SHOULD NOT page through
|
|
historical reactions; only the recent window matters.
|
|
|
|
## Wire format
|
|
|
|
```json
|
|
{
|
|
"kind": 7,
|
|
"pubkey": "<reactor pubkey hex>",
|
|
"tags": [
|
|
["a", "30312:<host pubkey hex>:<room d>", "<relay hint>"],
|
|
["p", "<target pubkey hex>"]?,
|
|
["emoji", "<shortcode>", "<image url>"]?
|
|
],
|
|
"content": "<emoji glyph or :shortcode:>",
|
|
...
|
|
}
|
|
```
|
|
|
|
`content` carries the reaction itself. Standard Unicode emoji glyphs are
|
|
used directly. Custom emoji follow NIP-30: `content = ":shortcode:"` with
|
|
a sibling `["emoji", shortcode, url]` tag.
|
|
|
|
A reaction MAY include a `["p", target]` tag scoping the reaction to a
|
|
specific speaker (renders over their avatar). With no `p` tag, the reaction
|
|
is room-wide (renders centered on the room canvas).
|
|
|
|
## Behavior
|
|
|
|
1. Reactors MUST emit `kind:7` events with at least one `a`-tag matching
|
|
EGG-01 and a non-empty `content` field.
|
|
2. Receivers MUST apply a 30-second sliding window: a reaction is rendered
|
|
from the moment it is observed until 30 seconds after its `created_at`,
|
|
then dropped from the floating overlay.
|
|
3. Receivers SHOULD throttle their reaction-overlay updates to at most 4 Hz
|
|
(250 ms minimum between repaints). At ~30 reactions per second a naive
|
|
recomposition can starve the audio decoder.
|
|
4. Receivers MUST tolerate unknown `content` values (e.g. a Unicode glyph
|
|
without a font fallback) by falling back to a generic indicator rather
|
|
than dropping the reaction.
|
|
5. Receivers MUST NOT auto-fetch the `["emoji", _, url]` image at the
|
|
moment of receipt — that opens an animated-emoji-driven DDoS vector.
|
|
Image fetch SHOULD be batched and rate-limited.
|
|
6. A reactor MAY include the same `a`-tagged reaction more than once
|
|
(e.g. spamming claps). Receivers MUST NOT de-duplicate by content
|
|
alone; events with different ids are always distinct.
|
|
|
|
## Example
|
|
|
|
A clap reaction targeted at a speaker:
|
|
|
|
```json
|
|
{
|
|
"kind": 7,
|
|
"pubkey": "ghi...audience",
|
|
"created_at": 1714003220,
|
|
"tags": [
|
|
["a", "30312:abchost:office-hours-2026-04"],
|
|
["p", "def...co"]
|
|
],
|
|
"content": "👏",
|
|
"id": "...",
|
|
"sig": "..."
|
|
}
|
|
```
|
|
|
|
A custom-emoji reaction (NIP-30):
|
|
|
|
```json
|
|
{
|
|
"kind": 7,
|
|
"pubkey": "ghi...audience",
|
|
"created_at": 1714003221,
|
|
"tags": [
|
|
["a", "30312:abchost:office-hours-2026-04"],
|
|
["emoji", "amethyst", "https://example/amethyst.png"]
|
|
],
|
|
"content": ":amethyst:",
|
|
"id": "...",
|
|
"sig": "..."
|
|
}
|
|
```
|
|
|
|
## Compatibility
|
|
|
|
EGG-06 is independent from EGG-05 (chat). A peer MAY implement either,
|
|
both, or neither without affecting interop on EGG-01 through EGG-04.
|
|
|
|
Future EGGs MAY introduce paid reactions (`kind:9735` zap receipts at the
|
|
same `a`-tag). Implementers SHOULD be prepared to source the reaction
|
|
overlay from both `kind:7` and `kind:9735` streams.
|