albBRAILLE
albBRAILLE is the site's braille transcription engine — a two-engine transcriber written in AdaLogic BASIC and compiled to JavaScript by the ALBW backend. It turns literary text into real UEB contracted braille and math notation into real Nemeth code, and it runs the public API at /api/braille. The second engine, albNEMETH, handles mathematics — the part of braille that almost nothing on the open web can produce on demand.
Why it exists
The site was built eyes-free first — the Linux handbook is written for blind readers, the library publishes braille-ready editions, and the wiki carries the Braille, Nemeth Braille Code, and Eyes-Free Linux trail as flagship content. A library of braille needs a transcriber, so one was written — in ALB, which turned out to be the right tool for it: deterministic rules, bounded tables, no hidden state.
The public API answers a gap that is easy to miss. Braille translation does exist elsewhere — liblouis transcribes UEB text, and commercial services embed Nemeth inside document workflows. But a free, public endpoint that turns an arbitrary math string into Nemeth braille is a different thing, and there essentially isn't one. That gap has gotten sharper with AI: a tutoring agent can write the words "factor x squared plus three x minus ten," but it cannot produce the braille. POST /api/braille with {"sys":"nemeth","txt":"x^2+3x-10=0"} closes that last inch — the envelope it returns (brf, uni, cells) drives an embosser, a screen, or a refreshable display from one call.
The two engines
| Engine | Input | Output |
|---|---|---|
| UEB Grade 2 | literary text | contracted braille — the shortforms and groupsigns real braille readers expect (the, quick, brown all contract) |
| UEB Grade 1 | literary text | uncontracted letter-for-cell — for learners and precise spellings |
| albNEMETH | latex-ish / asciimath math | Nemeth code — linear and spatial: matrices, cases, binomials, stacked arithmetic, long division |
The UEB pipeline
The literary engine runs text through five stages — a tokenizer, a shortform dictionary, a context-legality pass (a contraction is only legal in the positions UEB allows), a greedy longest-match selector, and finally a 6-bit cell stream. The legality stage is where real transcription happens — UEB is a context-sensitive code, not a lookup table, and whether st may contract depends on morpheme boundaries the engine has to reason about rather than memorize. Capitals get letter, word, and passage modes; numbers get the numeric indicator and numeric-space rules; errors land in a ledger rather than disappearing.
The Nemeth engine
albNEMETH takes the ascii/latex-ish grammar — x^2, sqrt(16), fractions, matrices — and emits Nemeth with proper indicators: the superscript and subscript marks, grouping symbols, the numeric indicator's level shifts. Beyond linear math it does spatial Nemeth: matrices laid out as braille tables, cases constructions, binomial coefficients, stacked arithmetic, and long division in its traditional carried layout. That matters because Nemeth is how blind STEM students actually read math — linear text is not a substitute.
Live Nemeth, inline: ⠰⠭⠘⠆⠐⠬⠼⠒⠰⠭⠤⠼⠂⠴⠀⠨⠅⠀⠼⠴x^2+3x-10=0 factors as ⠷⠰⠭⠬⠼⠢⠾⠷⠰⠭⠤⠼⠆⠾⠀⠨⠅⠀⠼⠴(x+5)(x-2)=0, and the quadratic formula sets as ⠰⠭⠀⠨⠅⠀⠷⠤⠰⠃⠬⠤⠎⠟⠗⠞⠷⠰⠃⠘⠆⠐⠤⠼⠲⠹⠁⠉⠾⠾⠌⠷⠼⠆⠰⠁⠾⠼x=(-b+-sqrt(b^2-4ac))/(2a). Those cells are not an image or a font trick — they are the engine's real output, transcribed server-side at render time, readable on a refreshable braille display or embossed straight from the page's own braille edition.
Validation
The UEB engine was checked the honest way — against liblouis, the reference open-source braille translator. On a 25,836-word corpus (a 13,747-word stratified sample, a 12,000-word a-initial slice, and 89 curated edge cases) the output matched en-ueb-g2.ctb cell-for-cell. That is the claim a transcription engine is entitled to make.
The API
| Endpoint | Purpose |
|---|---|
POST /api/braille | {sys, txt} → the envelope — sys is ueb, ueb-g1, or nemeth |
GET /api/braille | self-describing docs: systems, formats, limits, examples |
GET /api/braille/status | capability report |
POST /api/braille/keys | mint a free API key (raises the rate limit) |
No key is needed to try it — anonymous callers get a per-IP budget; a free key raises it. Keys arrive via X-API-Key or Authorization: Bearer. Underneath, the same engine also speaks JSON-RPC tools (br_ueb, br_ueb_g1, br_nemeth, br_translate) — the REST surface mirrors them.
In the wiki and across the site
The same engine serves three reading surfaces on top of the API:
[[math:expr]]— wiki markup that transcribesexprto Nemeth inline, as used above. Spatial input (matrices, cases) renders as a braille cell block.- Braille editions — every public wiki article carries a ⠃ Braille tab next to Edit and History, linking
/braille/wiki/<slug>— a UEB Grade 2 edition with Nemeth math — plus a.brfdownload paged for embossers.?grade=1switches to uncontracted. Static site pages have the same treatment under/braille/site/<path>. - The Braille Studio — a browser workbench: type text or math, get Unicode braille, the BRF stream, the raw cell masks, and a dot-grid — plus live
curlexamples for the API.
Editions are generated on demand and cached against the article's revision — an edit produces a new braille edition on the next read, not a stale one.
The honest gaps
No typeform, foreign-language, or italic markup; Nemeth arrays don't take colspecs and display environments aren't emitted; cells[] caps at 256 so long documents page per-paragraph. The Nemeth input is the engine's own ascii/latex-ish grammar, not full LaTeX \commands.
See also
- Braille · Nemeth Braille Code · Abraham Nemeth · Louis Braille
- Eyes-Free Linux · Speakup · BRLTTY
- ALB TypeScript backend — the ALBW backend that compiles the engine
- /library/ — the braille editions this engine exists for
GET /api/braille— the live API's own documentation