clone

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

main
nobel
README.md

nobel

nobel is a family of small nostr libraries for plain HTML, each a lightweight take on something bigger and each named for an element. Every library is one dependency-free script under 5kb unminified, and connects to the others only through DOM events, the way the fixi project libraries do. Attributes and events take n plus the element's symbol: nxe-filter, nhy:config, window.nhyCfg.

group library size (raw/br) miniature of provides prefix
period 1 (base) ๐Ÿ’ง hydrogen 2.8/1.2kb a relay pool relays, signing and the family's hooks nhy-
period 1 (base) ๐Ÿ”‘ helium 3.8/1.6kb @noble/secp256k1 keys, Schnorr signing and verification nhe-
alkali metal ๐Ÿ”‹ lithium 5.0/2.0kb Negentropy NIP-77 sync between argon and relays nli-
noble gas ๐Ÿ›ฐ๏ธ xenon 3.1/1.2kb a nostr client subscribe, render and publish in HTML nxe-
noble gas ๐Ÿ“ฆ argon 2.5/1.0kb a relay IndexedDB cache, offline-first feeds nar-
noble gas ๐Ÿ”— neon 3.9/1.8kb nip19 npub/nevent/naddr, linked content, times nne-
noble gas ๐Ÿชช radon 3.1/1.3kb a profile loader names, pictures, NIP-05 nrn-
noble gas ๐Ÿ‘ป oganesson 4.8/1.9kb a chat app's live layer presence, typing, cursors (ephemeral) nog-
halogen ๐Ÿงช fluorine 3.4/1.4kb NIP-44 encryption for helium's keys nfl-
halogen ๐Ÿ”Œ chlorine 4.6/1.8kb a NIP-46 client remote signing behind a NIP-07 face ncl-
halogen โœ‰๏ธ iodine 3.9/1.6kb an encrypted messenger NIP-17 private messages nio-
transition metal ๐Ÿฅ‡ gold 2.2/1.0kb a NIP-42 client relay AUTH for members-only relays nau-
transition metal โ˜ฟ๏ธ mercury 3.5/1.5kb rexi.js NIP-98 and Blossom signed HTTP nhg-
lanthanide ๐Ÿชž praseodymium 3.2/1.3kb fiatjaf's nostr-name and nostr-picture profile cards, chips, avatars, copy npr-
lanthanide ๐Ÿ”ด europium 2.7/1.1kb fiatjaf's nostr-note note embeds neu-
lanthanide ๐ŸŽจ cerium 2.8/0.9kb a theme the one stylesheet for the lanthanides nce-

Period 1 is the base, and it has exactly two elements: hydrogen moves events (relays, signatures and the three hooks nhy:config, nhy:event, nhy:message that every other library plugs into) and helium makes them trustworthy (keys, signing, verification). Neither needs the other; everything else builds on them. The alkali metals charge and flow: lithium syncs argon's store with relays. The noble gases are the core pieces for data and transport. The halogens handle secrets and trust. The transition metals do signed exchanges outside plain subscriptions. The lanthanides are visual presets: they only write markup you could have written by hand from the other libraries' attributes, in the light DOM, and leave anything you wrote alone. cerium holds all of their styling, in one zero-specificity layer you can override or drop.

<script src="hydrogen.js"></script>
<script src="helium.js"></script>
<script src="neon.js"></script>
<script src="argon.js"></script>
<script src="radon.js"></script>
<script src="xenon.js"></script>

<form nhy-relay="wss://relay.example" nxe-publish>
  <textarea name="content"></textarea><button>Post</button>
</form>
<ol nhy-relay="wss://relay.example" nxe-filter='{"kinds":[1],"limit":50}'>
  <template>
    <li><b nrn-profile="{pubkey}" nrn-field="name">{npub}</b> <time nne-ago="{created_at}">{ago}</time><p>{content}</p></li>
  </template>
</ol>

That page posts and reads notes, signs with a NIP-07 extension or a local key, shows names and linked content, and opens instantly from cache on reload.

Use it

Plain <script> tags work in any order: every library starts on DOMContentLoaded and looks its peers up only when it uses them. Load with async, or inject scripts after the page has loaded, and order starts to matter; use one file instead.

One file, just what you need. The site has a picker: tick libraries, it adds their dependencies and gives you a jsDelivr combine URL in the canonical order from scripts/libs.ts (base first, listeners next, xenon last), minified by jsDelivr:

<script src="https://cdn.jsdelivr.net/combine/gh/FelineStateMachine/nobel@main/hydrogen/hydrogen.min.js,gh/FelineStateMachine/nobel@main/xenon/xenon.min.js"></script>

One file, everything. https://felinestatemachine.github.io/nobel/dist/nobel.min.js (42kb, 15kb brotli), rebuilt on every push to main.

Separate files. https://cdn.jsdelivr.net/gh/FelineStateMachine/nobel@main/xenon/xenon.js, or copy them into your project: each is one file with no dependencies.

Replace @main with a tag or commit to pin a version; jsDelivr can serve a branch up to a day stale.

Naming

Each library is an element, and its prefix is n plus the element's symbol in lower case, so prefixes never collide. Elements with one-letter symbols add the next letter of their name that doesn't spell another element's symbol. Groups of the periodic table gather libraries by character, and new members join the group that fits. There is nothing about cryptocurrency here, by design.

Development

deno task dev     # http://localhost:8000/demo/ with an in-memory relay at /relay
deno task test    # parity, protocol and headless browser tests for every library
deno task size    # raw/gzip/brotli per library, fails over the 5kb budget
deno task bundle  # dist/nobel.js and dist/nobel.min.js
deno task site    # _site/: the static site published to GitHub Pages on every push to main

Demos: /demo/ (feed), /demo/iodine.html (private messages), /demo/oganesson.html (presence, typing, cursors), /demo/lanthanides.html (profiles and theme), /demo/europium.html (note embeds).

Some tests reach beyond the repo, and skip themselves when their dependency is missing:

  • lithium reconciles against bindws's Negentropy when ../bindws is checked out. NOBEL_RELAYS="wss://a ws://b" deno test -A test/live.test.js syncs against real relays.
  • chlorine runs against a real nak bunker when nak is on the PATH.
  • gold creates members-only tenants on a local tinyrelay container named noble-tiny.
  • mercury checks NIP-86 and Blossom on tinyrelay when NHG_TINY and NHG_KEY are set.
  • The browser tests use the Chromium headless shell in the Playwright cache, or CHROMIUM=/path/to/chrome.

License

Public domain, via the Unlicense.