oganesson.js is a miniature of the live layer of a big chat app: who's here, who's typing, where their cursor is. Any element can send an ephemeral event (kinds 20000-29999) on a heartbeat or on input, and any element can show the latest one per person from a template, removing it when it goes stale or its author leaves. It publishes and subscribes through xenon.js, signs through the same nhy:config hook (so helium.js or any other signer applies), and argon.js keeps none of it: argon keeps what lasts, oganesson handles what vanishes.
<main nog-room="lobby">
<ul nog-send="presence" nog-show="presence">
<template><li><b nrn-profile="{pubkey}" nrn-field="name">{npub}</b> {status}</li></template>
</ul>
<textarea nog-send="typing"></textarea>
<p nog-show="typing"><template><span><b nrn-profile="{pubkey}" nrn-field="name">someone</b> is typing</span></template></p>
</main>
The list announces you every minute and shows everyone else in the room, each once, until they go quiet or hide the page; the paragraph shows who is typing for five seconds after each keystroke.
| attribute | default | description |
|---|---|---|
nog-room |
none | Room id, sent as ["h", room] and filtered with #h. Inherited from the closest ancestor. Without it events have no h tag and shows are not filtered by room |
nog-send |
Topic this element publishes | |
nog-on |
input on inputs, textareas and selects |
Space-separated DOM events that publish. Pointer events send {"x","y"} as fractions of the element box. Without it (and not an input) the element sends a heartbeat every ttl/3 while the page is visible |
nog-status |
online |
Content of heartbeats, such as away |
nog-show |
Topic to show: one child per pubkey from the first element of the inner <template> (default <span>{pubkey}</span>), replaced on refresh, removed after the ttl |
|
nog-ttl |
per topic | Seconds an event stays shown, and the heartbeat period (ttl/3) |
nog-rate |
per topic | Minimum ms between sends. The latest throttled value is sent when the window ends |
nog-self |
Also show your own events (hidden by default; own pubkeys are learned from events you sign) | |
nog-ignore |
oganesson skips this element and its descendants |
Templates get xenon's fields (with neon.js {npub}, {ago}; with radon.js nrn-profile names), plus {status} and every key of JSON content, such as {x} and {y}, HTML-escaped. A cursor is <i style="left:calc({x} * 100%); top:calc({y} * 100%)">.
| topic | kind | ttl | rate | content |
|---|---|---|---|---|
presence |
20001 | 180 | 1000 | online, away, ... or offline |
typing |
20002 | 5 | 3000 | typing or stopped |
| anything else | nogCfg.kind (20078) |
30 | 1000 | the status, or JSON such as {"x":0.5,"y":0.25}; tagged ["t", topic] |
Presence and typing follow the convention shared by Block's Buzz and tinyrelay. Other topics, such as cursors, are only a convention of ours, on one configurable kind (window.nogCfg = {kind}).
| event | cancel to | detail |
|---|---|---|
nog:send |
skip sending | cfg (unsigned cfg.event) |
nog:shown |
event, fields, elt |
|
nog:expired |
keep the element | pubkey, elt |
nog:error |
cfg, error |
|
nog:process |
dispatch on an element to initialize new content |
offline and stopped remove the entry at once. Reading also accepts JSON {"status"} and {"typing":bool}, and false, idle, offline as stopped typing.stopped when the field is emptied or blurred. Hiding the page sends offline for heartbeats and stopped for active typing; showing it sends a heartbeat.oganesson.send(el, content) publishes through el's throttle, oganesson.leave() sends the goodbyes, oganesson.mine holds your pubkeys.Requires xenon.js.
oganesson.js (4.8/1.9kb raw/brotli), prefix nog-, needs hydrogen