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:/ (42kb, 15kb brotli), rebuilt on every push to main.
Separate files. https:/, 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: / (feed), / (private messages), / (presence, typing, cursors), / (profiles and theme), / (note embeds).
Some tests reach beyond the repo, and skip themselves when their dependency is missing:
- lithium reconciles against bindws's Negentropy when
../is checked out.bindws NOBEL_RELAYS="wss:/syncs against real relays./ a ws:/ / b" deno test -A test/ live.test.js - chlorine runs against a real
nak bunkerwhennakis 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_TINYandNHG_KEYare set. - The browser tests use the Chromium headless shell in the Playwright cache, or
CHROMIUM=/.path/ to/ chrome
License
Public domain, via the Unlicense.