structural-biology.com

ALPHABETTI: A protein sequence logo in 3D, wrapped around its own ESMFold-predicted structure

Originally published on marcdeller.com, which stays the source of record. Rendered here as published.

1UBQ · STRUCTURE OF UBIQUITIN REFINED AT 1.8 ANGSTROMS RESOLUTION · X-ray · 1.80 Å · Open the four lenses →

ALPHABETTI

A protein sequence logo, in three dimensions, wrapped around its own predicted structure.

live python flask gunicorn nginx sqlite three.js esmfold esm2 zerogpu biopython numpy freesasa dssp tests data phase licence author

🌐 Appalphabetti.mdeller.com✉️ Contactmarc@marcdeller.com🐙 GitHubbellcheddar/ALPHABETTI

🧬 Fold service: Dellboy/alphabetti-fold on Hugging Face ZeroGPU

ALPHABETTI showing ubiquitin in GIBBERISH mode: amino acid letters stacked along the predicted backbone, their heights proportional to information content in bits, coloured by residue chemistry against a dark ground

ALPHABETTI draws a protein’s own single-letter amino acid codes in 3D, positioned and oriented along an ESMFold-predicted backbone. Instead of a cartoon or a stick model, you get the letters themselves: stacked at each position by how strongly a protein language model expects them, tallest at the bottom, standing on the side chain.

Why it matters: a conventional sequence logo tells you which positions are conserved, but it does so on a flat strip that has been divorced from the structure, and it gets there through a multiple sequence alignment, inheriting every bias in the search-align-trim pipeline that produced it. ALPHABETTI has no alignment anywhere: it asks ESM-2 what it expects at each position, having first masked that position so the model cannot read the answer off its own input, and then wraps the answer onto the fold. Conserved buried core positions become tall single-letter towers, tolerant surface positions splay into short scruffy stacks, and helices read as spiral staircases of text. It is useful for: seeing at a glance which parts of a fold a model considers load-bearing, spotting exposed hydrophobic patches that drive aggregation or block crystallisation, finding positions where the wild-type residue is one the model would not have chosen, and producing something that people will actually share.

🧪 What the four tabs do

All four are computed once, shipped in one payload, and switch instantly with no further network round trip.

TabBackronymGlyph geometry is driven by
GIBBERISHGlyph Interface for Bits, Entropy and Residue Information in Structural HomologyESM-2 per-position probabilities, heights in bits of information content
BUMFLUFFBuried/Unburied Mapping of Fonts, Letters, Uncovered Faces and FoldsRelative solvent accessible surface area
BALDERDASHBayesian Amino-acid Letter Display of Estimated Residue Deviations And Substitution HotspotsVariant effect scores, ghost glyphs, ClinVar/gnomAD overlay
FOLDEROLFolding Of Letters Displayed En Route, Ordered LinearlyAn animated morph from a flat 2D logo strip into the 3D coordinates

BUMFLUFF mode: one letter per residue, height driven by relative solvent accessibility, coloured from deep blue for buried to amber for exposed, with exposed hydrophobic residues flagged in orange

📐 How a stack is built

H_i      = -sum_a p_a log2(p_a)      Shannon entropy, bits
R_i      = log2(20) - H_i            information content, maximum 4.322 bits
height_a = p_a * R_i                 per-letter height, bits

Letters are stacked along the residue’s own side-chain direction, each standing on the one below, so the total height of a stack is that position’s information content. A unit test checks this against hand-calculated values, because it is the difference between a quantitative picture and a decorative one.

No small-sample entropy correction is applied. The usual correction compensates for estimating a distribution from a finite number of aligned sequences; here there is no alignment and no sample, so correcting would subtract a bias that does not exist.

🔬 Scientific choices, and what they were checked against

QuantityMethodValidation
StructureESMFold (facebook/esmfold_v1)0.84 Å CA RMSD for ubiquitin against the 1UBQ crystal structure
ExpectationESM-2 650M (facebook/esm2_t33_650M_UR50D), masked marginalsUnmasked marginals return the wild type at 100 % of positions; see below
pLDDTESMFold’s B-factor columnNormalised and asserted to 0-100; a 0-1 scale renders as a uniformly unconfident protein
Relative SASAFreeSASA, 1.4 Šprobe, over Tien et al. (2013) theoretical maximaTotal SASA 4804 Ų for 1UBQ against a published value of about 4800
Secondary structureDSSP where present, else P-SEA from CA positions83.7 % three-state agreement with DSSP over 805 residues of ten chains
Virtual CβStandard tetrahedral construction from N, CA, C0.13 Å mean deviation from the real Cβ across all 70 non-glycine residues of 1UBQ
Variant scorelog p(mutant) - log p(wild type), ESM-1v conventionWild-type entry is exactly zero by construction; negative means deleterious

Glycine has no Cβ, so one is constructed and glycines are never skipped: a hole at every glycine would be a hole at exactly the positions where backbones turn.

📝 Masked marginals are the default, and that is a change from the brief

The original specification made masked marginals an opt-in toggle, “L times slower”. They are, and on a CPU that would settle it. On a GPU it does not, and the cheap option is actively misleading. Measured on ubiquitin:

 Wild-type marginalsMasked marginals
Top-1 equals wild type100 %80 %
Mean information content4.01 bits3.20 bits
Language model time0.03 s0.42 s (about 2.2 s at 400 residues)

An unmasked forward pass can read each residue off its own input, so it returns near-maximal confidence everywhere and GIBBERISH becomes a 3D rendering of the input sequence. Set ALPHABETTI_MASKED_MARGINALS=0 to compare.

Where it fails, kept on display

The GFP example is deliberately one that does not work. ESM-2 has almost no evolutionary signal for avGFP: masked marginals recover the wild-type residue at 10 % of positions against 8 % for a randomly shuffled version of the same sequence, and mean information content is 0.27 of a possible 4.322 bits. Because ESMFold’s trunk is ESM-2, the structure fails with it rather than independently, at mean pLDDT 42.8. The two never contradict each other, which is precisely why it is worth showing. Check the pLDDT before believing a picture.

BALDERDASH mode: wild-type letters at full size with dimmer ghost letters beneath showing the residues the model would have preferred

🏗️ Architecture

Browser (three.js r169, vanilla ES modules, no build step)
        |  JSON over fetch()
        v
Flask + Gunicorn on the mdeller.com droplet
        |-- SQLite cache, keyed on sha256(sequence)
        |-- bounded thread pool, job state in SQLite
        v  HTTPS
Hugging Face ZeroGPU Space
        |-- ESMFold          -> coordinates + pLDDT
        `-- ESM-2 650M       -> a 20 x L probability matrix

The fold does not run on the droplet, and cannot. That box has 3.9 GB of RAM with about 2.0 GB free, two cores, and eight other applications already on it; the esmfold_v1 checkpoint alone is 7.9 GB of fp32 weights, and a 400-residue fold needs several more gigabytes for the L x L pair representation. It is short by a factor of four to six.

So the Space returns nothing but coordinates and probabilities, and every derived quantity is computed in this repository — information content, entropy, variant scores, accessibility, secondary structure, per-residue frames — in modules that need neither a GPU nor a network and are unit-tested without one. The science does not move when the compute does.

That decision also removed Redis and RQ. With no models to hold, a job spends its entire life waiting on one HTTPS request, which is what threads are for; job state lives in SQLite so both Gunicorn workers can see it.

⚙️ Options

Every setting is an environment variable. See .env.example.

VariableDefaultWhat it does
ALPHABETTI_FOLD_BACKENDhf_spacehf_space, local (torch in-process, needs ~16 GB), or none (cache only)
ALPHABETTI_HF_SPACEDellboy/alphabetti-foldThe Space that holds the models
HF_TOKEN(none)Required in practice: the anonymous ZeroGPU quota is a handful of folds and runs out with an error that does not mention quota
ALPHABETTI_MASKED_MARGINALS1Masked marginals; 0 gives the faster, misleading unmasked pass
ALPHABETTI_MAX_LENGTH400Longer input is refused with an offer to truncate, naming the exact range kept
ALPHABETTI_MIN_LENGTH10 
ALPHABETTI_FOLD_TIMEOUT900Seconds before a fold is given up on cleanly
ALPHABETTI_MAX_CONCURRENT2Concurrent folds; ZeroGPU serialises anyway and quota is per account
ALPHABETTI_TOP_K6Amino acids per position carried in the payload
ALPHABETTI_CACHEinstance/alphabetti.sqliteCache database
ALPHABETTI_ENABLE_UNIPROT1Accession and entry-name lookup
ALPHABETTI_ENABLE_VARIANTS1EBI Proteins API overlay for BALDERDASH

📤 Outputs

FormatRouteNotes
PDB/api/download/<id>.pdbThe predicted structure, pLDDT in the B-factor column
JSON/api/download/<id>.jsonThe full payload that drives all four tabs
CSV/api/download/<id>.csvPer residue: resnum, aa, pLDDT, RSA, SASA, SS, bits, entropy, surprise
GLBin-appBaked instanced geometry with vertex colours, for Blender or AR
STLin-appFor printing; letters are separate shells and the app says so
PNGin-app1x, 2x, 4x, with a transparent-background option
GIFin-appOne FOLDEROL loop, with a resolution selector

🚀 Running it

git clone https://github.com/bellcheddar/ALPHABETTI.git
cd ALPHABETTI
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .env          # add HF_TOKEN
.venv/bin/python app.py       # http://127.0.0.1:8006

The four examples are committed as computed payloads, so the app shows a rotating protein before it has ever reached a GPU.

.venv/bin/python -m pytest tests/ -q          # 47 tests, no GPU, no network
.venv/bin/python scripts/prewarm.py           # recompute the examples
.venv/bin/python scripts/make_typeface.py /path/to/font.ttf out.json 700
.venv/bin/python scripts/make_icon.py         # icon, favicon, OG card

Deployment: deploy/provision.sh once, deploy/deploy.sh thereafter.

✅ To Do

  • ✅ Backend science modules — geometry, language model, accessibility and sequence handling, all pure numpy and Biopython, unit-tested with no GPU and no network.
  • ✅ Per-residue frames — orthonormal, right-handed, with a degenerate-case guard and both termini handled; mirrored function for function in orientation.js for FOLDEROL.
  • ✅ Virtual Cβ for glycine — validated to 0.13 Å mean against real Cβ positions in 1UBQ. Never skipped.
  • ✅ Fixed a 180° dihedral sign error — helices sat at −129° where P-SEA publishes +50°, so every angle criterion silently failed. The CA-only secondary structure assignment went from 55 % to 83.7 % against DSSP. This matters because mkdssp is not on the droplet, making the fallback the production path.
  • ✅ Caught DSSP failing on every structure — mkdssp rejects any file with no PDB HEADER line and ESMFold emits none, while a bare except: pass reported it as merely absent.
  • ✅ ZeroGPU fold service — ESMFold and ESM-2 650M behind a JSON API, 12.7 s wall for a first fold against an estimated 3-8 minutes on a CPU droplet.
  • ✅ Masked marginals by default — after measuring that unmasked marginals return the wild type at 100 % of positions.
  • ✅ Instanced glyph renderer — one InstancedMesh per amino acid, twenty draw calls regardless of chain length.
  • ✅ Baloo 2 to typeface.json — with the curve argument order verified against the source outlines to 0.34 %.
  • ✅ All four tabs against a single payload, switching with no network round trip.
  • ✅ Four examples spanning the fold classes — beta-grasp, mixed alpha/beta, all-alpha, and a beta barrel that deliberately fails.
  • ✅ Exports — GLB, STL, PNG at 1x/2x/4x, and an animated GIF over one FOLDEROL loop.
  • ✅ 47 tests, including two regressions for bugs found during the build.
  • ✅ BENCHMARKS.md with real timings from the machines that serve the app.
  • ✅ Neon Signage visual direction, chosen from five rendered candidates.
  • ⬜ DNS and TLS — alphabetti.mdeller.com needs an A record to 45.55.102.228 and a certbot certificate; mdeller.com’s certificate does not cover subdomains.
  • ⬜ Add to the mdeller.com launcher — one entry at the top of apps.json, with the beacon pointing at the 3D typeface, since a scanner never fetches it.
  • ⬜ BALDERDASH substitution heatmap panel — the 20 x L matrix is already in the payload and colour-mapped; the clickable panel that flies the camera to a position is not built.
  • ⬜ Mobile testing on a real phone — the bottom-sheet layout and pinch-zoom are written but have only been checked at emulated widths.
  • ⬜ Verify GLB and STL open in Blender — the exporters run and produce files of a sensible size, but nobody has opened one yet.
  • ⬜ Revisit the 400-residue cap — set against an assumed CPU fold of minutes; at 32 s on ZeroGPU the honest constraint is now quota and payload size.
  • ⬜ A second fold backend — the Space is a single point of failure, and FoldBackend already has the seam for a fallback.

📄 Licence

MIT.

🙏 Citations

  • Lin Z, Akin H, Rao R, et al. (2023) Evolutionary-scale prediction of atomic-level protein structure with a language model. Science 379:1123-1130.
  • Meier J, Rao R, Verkuil R, et al. (2021) Language models enable zero-shot prediction of the effects of mutations on protein function. NeurIPS.
  • Tien MZ, Meyer AG, Sydykova DK, Spielman SJ, Wilke CO (2013) Maximum allowed solvent accessibilities of residues in proteins. PLoS ONE 8(11):e80635.
  • Labesse G, Colloc’h N, Pothier J, Mornon JP (1997) P-SEA: a new efficient assignment of secondary structure from Cα trace of proteins. CABIOS 13:291-295.
  • Schneider TD, Stephens RM (1990) Sequence logos: a new way to display consensus sequences. Nucleic Acids Research 18:6097-6100.
  • Kabsch W, Sander C (1983) Dictionary of protein secondary structure. Biopolymers 22:2577-2637.
  • Kyte J, Doolittle RF (1982) A simple method for displaying the hydropathic character of a protein. J Mol Biol 157:105-132.

Built by Marc C. Deller, D.Phil. · marcdeller.com · marc@marcdeller.com


👤 Author

Marc C. Deller, D.Phil.
Structural biologist & drug discovery scientist

🌐marcdeller.com✉️marc@marcdeller.com🐙github.com/bellcheddar/ALPHABETTI.git

Read the original on marcdeller.com.