atproto git client
README.md

atgc brand assets #

The mark is two base pairs: adenine bonded to thymine over guanine bonded to cytosine. That is not decoration around the name, it is the name — atgc is exactly the letters of those two pairs, so the logo and the word say the same thing twice.

Everything here is generated, not drawn by hand, from the same facts src/about.rs uses to draw atgc about:

  • A green, T red, G yellow, C cyan — the chromatogram convention, and the same four colors base_color() picks out of the ANSI bright codes.
  • Two bonds for A–T, three for G–C — the count is real chemistry, and it is why the two rungs in the mark are not identical. about makes the same distinction with - and =.
  • Muted gray for everything that is not a base — strands and bonds, matching MUTED.
  • Rounded corners, from the ╭─ atgc ─╮ panel.
  • The name is lowercase, always.

What to reach for #

Need File
Favicon favicon.ico (16/32/48), or png/icon-32.png
Web app icon png/icon-192.png, png/icon-512.png
iOS home screen apple-touch-icon.png (180, full-bleed — iOS masks it itself)
Profile avatar, circular png/avatar-circle-512.png
Profile avatar, upload form png/avatar-square-512.png (full-bleed; let the site crop)
Mark on your own background svg/logomark-dark.svg, svg/logomark-light.svg
Name alone svg/wordmark-dark.svg, svg/wordmark-light.svg
Mark and name together svg/lockup-dark.svg, svg/lockup-light.svg
Mark and name, background unknown svg/lockup.svg, png/lockup-512.png
OpenGraph / social preview png/social-card-1200x630.png

Prefer the SVG in svg/ wherever the target renders it; the PNGs in png/ exist for the places that will not.

The social card is the mark and the name on the field of DNA, not on a flat plate: it stands in for atgc where nobody has opened anything yet — a link pasted into a chat — and both the login page atgc serves and atgc.codes greet a reader with the same field. gen.py's field_rungs is a port of draw_field in src/art.rs, constant for constant, so it is that field and not one that resembles it. What differs is the ink: a terminal draws a rung as A---T, and here the same cells are drawn in the mark's own dots and hydrogen bonds, because a card is vector art beside a vector mark.

svg/wordmark-mono.svg draws in currentColor, for a context that needs one ink — a stamp, an embroidery, a single-color print.

Light and dark #

Two palettes ship, and they are not the same colors dimmed. On white the bases go darker and the strand gray goes from #7d8590 to #57606a, because a strand at a third opacity reads on #0d1117 and disappears on #ffffff. Use the -light files on light backgrounds. svg/logomark.svg and svg/lockup.svg split the difference with a gray that carries on either, for when you cannot know.

A Markdown file is the usual place you cannot know. A forge that themes itself — Tangled swaps a dark class on the page, GitHub swaps on the reader's setting — gives the image no way to ask which one it got, and the <picture> trick that answers this on GitHub does not survive Tangled's HTML sanitizer, which drops the <picture> element and leaves whichever <img> was inside it. So the PNGs a README reaches for — png/logomark-*.png, png/lockup-*.png — are rendered from the neutral masters, and a README should use those rather than a -dark raster.

Palette #

Dark bg Light bg
A — adenine #5ddc7c #1a9850
T — thymine #ff7f74 #d33f36
G — guanine #f2c94c #b8860b
C — cytosine #4fd6e0 #0e8ba0
strand / bond #7d8590 #57606a
plate #0d1117 #ffffff

Rebuilding #

python3 build.py <output-dir>          # write the assets
python3 build.py --check <output-dir>  # verify they match the generator

Needs Pillow and a google-chrome on PATH — Chrome is the rasteriser. gen.py holds the geometry, the palettes and the field; build.py decides which files come out of it. Change a color in gen.py and every asset here changes together, which is the point of keeping it generated.

--check rebuilds into a scratch directory and compares byte for byte, then exits non-zero on the first difference. It is the one test worth having for generated files: it catches a PNG touched up by hand, a color changed in gen.py without a rebuild, and a file that stopped being generated at all. It only works because the generator is deterministic — no timestamps, no randomness — so keep it that way.

Using it #

The mark wants air: keep clear space around it of at least the radius of one base dot. Do not recolor the bases, restretch the mark, or set the name in another face — the four colors and the letterforms are the whole identity. Do not add a third rung; two is the name.