clone

tiny dependency-free nostr libraries for plain html, each under 5kb and named for an element. public domain

main
nobel / oganesson
README.md

👻 oganesson.js - live and ephemeral

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.

Attributes

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%)">.

Topics

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}).

Events

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

Behavior

  • Readers drop events more than 5s in the future or older than their ttl, and events older than the one shown for that pubkey.
  • offline and stopped remove the entry at once. Reading also accepts JSON {"status"} and {"typing":bool}, and false, idle, offline as stopped typing.
  • Typing sends 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.
  • Seeing a new pubkey makes this page's heartbeats in the same room and topic send right away, so newcomers don't wait a minute.
  • oganesson.send(el, content) publishes through el's throttle, oganesson.leave() sends the goodbyes, oganesson.mine holds your pubkeys.

Caveats

  • Every heartbeat, keystroke burst and cursor move is a signature. A NIP-07 extension may prompt each time, so this works best with helium.js's local key or an extension set to auto-approve these kinds.
  • Buzz and tinyrelay members-only rooms may require NIP-42 AUTH, which a future family library will handle.

Requires xenon.js.