# Icon Registry

A set of 116 monochrome 7x7 pixel icons.

Each icon is a 7x7 grid of on/off pixels - 49 bits of data. To keep this
registry compact, every icon is stored as a **single base36 code** (<=10
characters) instead of a nested array or a bulky base64 string.

Build the icons at [/icons](https://superwall.com/icons).

## Encoding

A 7x7 grid holds 49 bits. That fits exactly in one JavaScript number
(2^49 ~= 5.6 x 10^14, safely under `Number.MAX_SAFE_INTEGER` = 2^53 - 1), so the
whole icon is just an integer written in base36:

```
grid (7x7)  ->  flatten row-by-row  ->  49-bit binary  ->  integer  ->  base36
```

- **Encode:** `parseInt(bits, 2).toString(36)`
- **Decode:** `parseInt(code, 36).toString(2).padStart(49, "0")`

Leading `0` rows make the integer smaller, so many codes are shorter than 10
characters. The `padStart(49, "0")` on decode restores any leading zeros that
were dropped - the grid width is always a fixed 49 bits.

## Rendering (React)

Drop-in component. Pass any `icon` code from the registry below.

```jsx
import React from "react";

// base36 code -> 7x7 grid of 0/1
function decodeIcon(code) {
  const bits = parseInt(code, 36).toString(2).padStart(49, "0");
  const rows = [];
  for (let y = 0; y < 7; y++) {
    rows.push(bits.slice(y * 7, y * 7 + 7).split("").map(Number));
  }
  return rows;
}

export function GridIcon({ icon, size = 28, fill = "currentColor", title }) {
  const grid = decodeIcon(icon);

  // Run-length encode each row into horizontal SVG path segments
  const paths = grid.flatMap((row, y) => {
    const segs = [];
    let start = null;
    for (let x = 0; x <= row.length; x++) {
      const filled = row[x] === 1;
      if (filled && start === null) start = x;
      if ((!filled || x === row.length) && start !== null) {
        segs.push(`M${start} ${y}h${x - start}v1H${start}z`);
        start = null;
      }
    }
    return segs;
  });

  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 7 7"
      width={size}
      height={size}
      shapeRendering="crispEdges"
      fill={fill}
      role={title ? "img" : undefined}
      aria-label={title}
      aria-hidden={title ? undefined : true}
    >
      {paths.map((d, i) => (
        <path key={i} d={d} />
      ))}
    </svg>
  );
}

// Usage (face):
// <GridIcon icon="37bq35ugo" title="Face" />
```

The `viewBox="0 0 7 7"` with `shape-rendering="crispEdges"` keeps pixels sharp at
any size. `fill="currentColor"` makes the icon inherit its text color.

## Registry

Format: `icon_name: base36`

```
add_element: 37bq35ugo
ai: 1gglfkrk0
alarm: 1i55ix9cce
arrow: ctep3l1xk
arrow_diagonal: r6wk64n4
arrow_up_filled: cth7redqg
at_mention: 5isgr8u9of
bag: 2p2nxz42db
bar_chart: 2slxn4dhq7
bell: 182h2po4y0
bell_add: sjfneakg8
branch: nhdwdr2tr
calculator: 5isky70oov
calendar: 5isky70ohr
cart: 46e9184gzb
checkmark: g3hu328
chevron: 107uy9s
chevron_offset: 3kryoohs
chevron_small: 3kry1urk
circle: ce71vp4w
circle_filled: choc27eo
click: 1f95qzkrup
clock: 18bjbqzva4
color_swatch: 5jh46ngem7
compose: 59g2u73p4v
computer: 5isda98bpa
copy: 1cjntshkl8
credit_card: 1jwseiyyo
crown: 374cevm01q
cursor: 5es9ywesqp
docs: 5isgqjt6gv
dollar: d8a4q8jk8
download: ckmym0jjz
ellipses: 1gfv9c
enter: 5i05489p8w
exclamation: 5jg8d7kq2n
expand_all: 56qcw9z5yv
expand_diagonal: 5895f7vuz3
eye: ce8ekpvk
filter: 5jjjiya2a0
flag: 3s4jyxz5of
fork_down: ckiv3rf7t
gauge: chqjbog0
gift: 1i1v5dsohj
glasses: fqsderk
globe: 2q4zy1rtmm
grid: 1v107i2dnu
grid_list: 4vobrlxomo
grip_horizontal: 56gtw5c
grip_vertical: 8rpmzthc
heart: o45kx1jc
hourglass: 2pex23zl8e
import: 4vfv0din3k
infinity: 6q9xfy8
info: 18bkbgyrdo
kebab: 3ia974lc
layers: b00dyempc
line_chart_arrow_down: 2sr7s8kbr3
line_chart_arrow_up: 2sqbq4hxmn
link: 1geh89e2o
lock: 2p2zcokxz3
logout: 4vfu9qjii8
mail: 5j7cfpn8qn
maximize: 56bdqsrgmv
menu: 1jort0neo
message: 5isda98if4
minimize: vfn28h9g4
moon: 187w2pyi3g
multiply: 2tqzem7txd
music: 1cjbxe4yrb
music_note: cma4u95x4
next: 34oprsz9e0
notification: 5ckqzp9a7z
page: 5e67n61b7j
panel: 5izftsal1b
pause: 5jjp5hrsvz
pencil: 4rhjtb59c
person: 5isfr1ak1r
person_alt: 18f048vn6q
play: 5jco3i1q0v
plug: vfg2cnsi0
plus: ckiv34f0o
plus_2: 3jbn981s
plus_filled: 5jg8bc2nlr
pointer: 17weczf34v
quote: 1gl5v064g
redo: 5e5f1o5wqn
search: 2g4y5deqyp
segment: ov69ljibz
select: 2ca6qs41fa
share: ctemv2c5b
shield: 36y7fepzq4
sliders: cgkk1n9bk
sparkles: 6acpcpusg
split_cross: ckiut4tmw
square: ravgips0
square_add: 4ylegp7f27
square_filled: recqp81s
star: 36bi9fcnk9
sun: cvzoup4i0
swap: pcfq4kkjo
switch_off: 1jygvllkw
switch_on: 1k3osvczk
tag: 1qcopvz0w
target: 56beracvlj
terminal: 1e2zgs3g5b
transparent: 3p16fbjx3p
trash: 17wnk3d8vy
trend_down: 2sy9kq1m67
trend_up: 2skm1i84u7
undo: 1cjpa7lfjz
upload: ctemufbzz
wand: tosttdwtc
wand_plus: 1fahpxjcq8
x_filled: 5j4shi46bj
zap: crocmavwo
```
