# ShapeAddress format, version 2

Status: draft for v0.3 (2026-10-19). Normative words: must, should.

## 1. Model

An input is a byte string of length 1 or more. A **dictionary** is an ordered list of `n` colours and an ordered list of `m` glyphs with `n × m = 256`, identified by a lowercase id (`[a-z0-9][a-z0-9-]*`). Each byte `b` maps to one **cell**:

```
shape  = b mod m          (index into glyphs)
colour = (b - shape) / m  (index into colours)
b      = colour × m + shape
```

For the default dictionary `sa330` (`n = 8`, `m = 32`) this is `colour = b >> 5`, `shape = b & 31`.

Inputs: hex strings (optional `0x`, case-insensitive, even length), UTF-8 text, or raw bytes. EVM addresses are 20 bytes and render as 20 cells. Checksum casing (EIP-55) never changes the picture.

## 2. Layouts

Layouts are pluggable (`layouts.register(id, fn)`); the layout id is written on the SVG root. The two reference layouts:

- **grid**: 5 columns, cells in reading order (left to right, top to bottom), cell size 100, gap `g` (default 8). ViewBox `(5·100 + 4g) × (rows·100 + (rows−1)g)`.
- **coin**: cells on a ring clockwise starting just after 12 o'clock (a notch marks the start), plus a centre cell whose byte is the XOR of all data bytes. A reader verifies the ring against the centre.

## 3. SVG carrier

Every rendered SVG root carries `data-dict="<id>"` and `data-sa="2:<id>:<layout>:<hex>"`. Each cell is a `<g data-i="<index>" data-shape="<glyph name>" data-color="<colour name>">`; the checksum cell has `data-i="-1"`. A decoder must recover the bytes from the cells' names using the dictionary named on the root and must not rely on the `data-sa` hex, which is informative.

## 4. Spoken form

The legend of a cell is `<colour word> <glyph word>`, read in cell order. Words are the dictionary's; `sa330` byte `0x00` is "red circle", `0xff` is "pink lens". A dictionary entry has one canonical `name` (lowercase ASCII, used in the SVG), optional `labels` per language (`{ ar: 'دائرة', pt: 'círculo' }`) and optional `aliases` (any other word a reader may use). A reader may say the words in either order within a cell, in any language the dictionary carries; the reference `fromLegend()` folds case, accents and Arabic diacritics and accepts cells separated by commas, semicolons or newlines. Within one dictionary a word must name exactly one cell part; registration rejects a word that names two.

## 5. Options that do not change the data

size, style (tile or glyph), cell shape, gap, radius, background, palette (cvd hatching), labels, title, highlight. Changing any of them changes the picture but not the decoded bytes.

## 6. Dictionaries

A dictionary id names an exact glyph and colour list forever. Changing a glyph or colour requires a new id. Registered ids in this repository: `sa330` (32 owned glyphs, 8 hues, MIT), `fa330` (the original lab set, Font Awesome Free glyphs, CC BY 4.0). Third parties may register their own; ids starting with `sa` are reserved for ShapeAddress.

## 7. Test vectors

`spec/test-vectors.json` lists inputs, options, expected hex, legend and the SHA-256 of the SVG string produced by the reference implementation. A port is conformant when it reproduces the hex and legend for every vector and decodes the reference SVGs; byte-identical SVG is required only for implementations that claim to be the reference renderer.
