glyphbyte

One drawn glyph is one byte.

Draw the first bytes of a nostr event id or pubkey on any surface with any pen. The alphabet has sixteen glyphs; each one sits in a square or a circle, outline or filled, in one of four rotations, so every byte is exactly one drawing and every drawing is one byte. A phone reads the row back on the device, and a relay resolves the bytes to the event or the profile they name.

How it works

  1. Draw

    Take the first six bytes of an id or a pubkey. Each byte names one glyph, a rotation, outline or filled, and a square or a circle frame. Draw them left to right, each in its own frame, underline the whole row, and put a fat dot at the start of the line.

    Six framed glyphs in a row above an underline that starts with a fat dot
    e8ed3798c6ff as the reference renderer draws it, one byte per frame:
    1. e8 trapezoid rotated 180 deg, outline, square frame
    2. ed trapezoid rotated 270 deg, outline, circle frame
    3. 37 crown rotated 90 deg, filled, circle frame
    4. 98 heart rotated 180 deg, outline, square frame
    5. c6 snowman rotated 90 deg, filled, square frame
    6. ff pacman rotated 270 deg, filled, circle frame
  2. Read

    Open the reader on a phone and take a photo. It finds the frames, the underline and the dot, straightens each frame, and classifies the glyph, its rotation and its fill with a small neural network, all in JavaScript on the device. The underline tells it which way is up, so a photo taken sideways reads the same.

    Where a glyph is unclear the reader keeps the alternatives instead of guessing, and returns the most probable whole readings, ranked. A missing glyph is never dropped silently, because that would shift every byte after it.

    A marker drawing of six glyphs on a dot-grid notebook page
    a marker on a notebook page: read as e8ed3798c6ff on a phone in under a second
  3. Look up

    The bytes are a prefix. The reader asks a relay for every candidate reading at once, as an event id prefix and as a pubkey prefix, and shows what comes back with the author's profile. You confirm which one you meant. A wrong candidate matches nothing, which is why there is no checksum.

How well does it work

On the synthetic benchmark in BENCH.md (200 scenes, 996 symbols, random handwriting severity, perspective, lighting, blur and JPEG on photographed backdrops) the reference reader finds 0.862 of the frames, reads 0.922 of the symbol bytes correctly where the frame count matched, and gets the whole row right as its first answer 0.535 of the time. Missing frames, not misread glyphs, are the main loss. The classifier alone scores 98.6% on held-out patches, 97.6% for the smaller model that ships in the reader. Real handwriting has one measurement so far: the notebook photo above, which the reader returns exactly.

The alphabet

The GlyphByte sheet: sixteen rows of glyphs, eight columns of rotations and fills, in square and circle frames
Rows are the 16 glyphs, top to bottom in index order. Columns are the four rotations, 0, 90, 180 and 270 degrees clockwise, first as outlines and then filled, in alternating square and circle frames.
bitsfieldvalues
7..4symbolindex 0 to 15, the row on the sheet
3..2rotationquarter turns clockwise from upright: 0, 90, 180, 270 degrees
1fill0 outline, 1 filled
0frame0 square, 1 circle

byte = symbol << 4 | rotation << 2 | fill << 1 | frame, so 16 x 4 x 2 x 2 = 256. All 256 drawings are listed in the spec's test vectors.

Draw a row

Look it up

The reader sends every candidate reading in one request, as an ids prefix and as an authors prefix for kind 0 profiles:

["REQ", "gb", {"ids": ["e8ed3798c6ff"]}, {"authors": ["e8ed3798c6ff"], "kinds": [0]}]

Prefix matching in ids and authors was part of the first NIP-01 and was later removed from the text, so it needs a relay that still supports it. As of 2026-09 grain honours prefixes of any length in both fields; strfry and khatru currently do not (strfry answers CLOSED, khatru returns nothing). The reader defaults to wss://wheat.oslim.dev, a grain relay, and tests whichever relay you enter once, by fetching one event and asking for it again by an 8-character prefix, then tells you when a relay rejects or ignores partial queries.

Results show the author's profile and which candidate they matched, and the person confirms which one they meant. A prefix is a pointer, not a proof: the resolved full id or pubkey is the reference, never the drawn bytes.

Get it

The whole reader runs in the browser: the detector, the network weights and the glyph shapes are inline in one page, and nothing leaves the device except the relay queries you can see on the page. The same file is also a napplet (NIP-5D) that a nostr shell can load in a sandboxed iframe.