A halftone screen-print record sleeve in worn cream stock, with a small black paper sticker reading Wax+Wires in red letters at the top left corner. Centered on the sleeve, a large red hexagon contains a cream vertical rod crossed by four horizontal bars, shaped like a shock absorber or suspension strut. Heavy print wear, cracked ink, and edge damage throughout.

Essay

Introducing Englyn: The Ramp Was Load-Bearing

Accessibility work spent twenty-five years losing to ship dates. Software is now used by things that can't see, and the argument changed under everybody's feet.

· 20 min read

Listen

Side A — The Read

This recording may be out of date. The text was edited after this audio was recorded.

About this recording

Nature
Human-recorded speech, not synthetic
Recorded by
Micah Eberman, using GarageBand 10.4.12
Source text
Introducing Englyn: The Ramp Was Load-Bearing, written by Micah Eberman
Recorded on
Reviewed by
Micah Eberman,
Owner
Micah Eberman
About this recording
Nature
Human-recorded speech, not synthetic
Recorded by
Micah Eberman, using GarageBand 10.4.12
Source text
Introducing Englyn: The Ramp Was Load-Bearing, written by Micah Eberman
Recorded on
Reviewed by
Micah Eberman,
Owner
Micah Eberman

The text on this page is the transcript of this reading.

Read

Essay briefing

The claim: the argument for accessible software has been losing to sprint deadlines for twenty-five years, and it just changed, because software is now used, in volume, by agents that can’t see a page any better than a screen reader user can. The floor already existed, the W3C’s own POUR principles. What was missing is a fifth mark: a claim a consumer can check, not merely receive. This essay makes that case in seven moves: what actually changed and who else needs the answer now, the missing fifth mark and the 2002 standard it guards against, a defect that got past four green automated checks on this very site, what Englyn actually is and why it has to be a standard rather than a library, a tour of what is published here and how to run it against your own work, where the tiers and the published limits sit, and an ask aimed specifically at people who use assistive technology every day. Reading time: about twenty minutes. Three thousand, eight hundred and fourteen words. Two links close the essay: the specification itself and its source repository. Both are real addresses; the repository goes live in a second, separate step, so either may not resolve yet.

I have been making the case for accessible software for a long time, and for most of that time I have been losing.

Not losing arguments. Winning arguments and losing sprints. Everybody nods. The ticket gets written, the ticket gets estimated, the estimate gets cut, and the person who couldn’t use the product still can’t use it. Then the next quarter starts.

If you have done this work you know the shape of it. If you haven’t, the short version is that being right has never been the bottleneck.

What changed isn’t the argument. It is who else needs the answer.

Section 1 of 12.

Software is now being used, in volume, by things that can’t see.

An agent hitting your interface has the same problem a screen reader user has had since 1999. It can’t see your layout. It can’t read meaning off position. It can’t tell that the red button is dangerous, because red is a color and a color is a pixel. It needs the structure stated, not implied.

That isn’t a metaphor and it isn’t a coincidence. It is the same requirement, arriving with a budget attached.

Which puts a lot of us in a strange position. The thing I couldn’t get funded on the grounds that all people deserve to use software is now getting funded on the grounds that all agents need to parse it. I have complicated feelings about that. I am also going to take the money and build the ramp.

The curb cut, and why I keep coming back to it

Section 2 of 12.

Curb cuts were fought for by disabled activists. They were resisted, at the time, as an expensive accommodation for a minority.

Now they carry strollers, delivery trolleys, suitcases, bicycles, and anybody with a bad knee. The people who needed them most were never the only ones who benefited. They were the ones who couldn’t proceed without them.

Semantic structure is the ramp. Headings that mean something. Regions that say what they are. Consequences stated before you act rather than after. It was built for assistive technology, and it is now what an agent needs to act on your page without guessing.

So here is the part I want to be careful about, because it is the part that gets me suspicious of my own argument.

This is the rare case where doing right by people isn’t a cost you absorb. The work that makes your product survive contact with an agent is the same work that makes it usable by somebody who can’t see it. You don’t have to choose. You were probably going to build half of it anyway.

That’s a good deal and I’m not going to pretend it is charity. Take the ride, and take the credit for showing up. Then go and find out who was already here, because they left you notes.

What is actually missing

Section 3 of 12.

Here is the specific gap, and it is narrower than “accessibility is hard.”

The floor already exists. POUR is the organizing principle under the Web Content Accessibility Guidelines: content must be Perceivable, Operable, Understandable, and Robust. It has been there since 1999. It was built by people doing this work before any of it was fashionable, and it is a genuine achievement.

Englyn has five marks. Four of them are POUR, restated for a consumer POUR wasn’t written for. Observable is Perceivable. Recoverable is Operable. Explicit is Understandable. Typed is Robust. I’m not claiming those four. If you have done accessibility work, you are further along here than you expect.

The fifth one is the reason I wrote anything down.

Verifiable: a consumer must be able to check a claim, not merely receive it.

POUR has no verification principle, and that isn’t an oversight. POUR was written for documents, and documents make no claims. A page that says “Contact Us” isn’t asserting anything you could be wrong about. It is text. You read it or you don’t.

An interface an agent acts on isn’t a document. It is a transaction. When your markup says an action is safe, or reversible, or complete, that’s a claim with consequences, and the consumer needs a way to check it rather than trust it.

A description is adequate when a human is in the loop to catch the lie. It isn’t adequate when nothing is.

The failure mode I built this against

Section 4 of 12.

In 2002 the W3C published P3P, a privacy specification. Internet Explorer checked that a policy string was present. It never checked whether it was true.

So sites shipped a string, the check passed, and behavior never changed. Google’s read, in production, for years:

P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."

The check passed. The W3C working group had gone quiet years earlier, and Microsoft finally pulled P3P support out of Internet Explorer and Edge around 2018.

Presence isn’t conformance. Any standard that can be satisfied by declaring something will be, and the declaration will be false, and the tooling will report success.

And then it happened to me

Section 5 of 12.

Every heading on my site is written in sentence case. CSS renders them as capitals. Correct source, correct rendering, and a defect underneath it.

WebKit hands the style-transformed string to the accessibility tree. So VoiceOver received “US” and read it as the country.

“What this buys us.” became… “What this buys U-S.”

Six instances across four pages. At the time: axe reported zero violations. html-validate passed. My own checker passed. The DOM was perfect. Four layers of automated testing, all green, on a page a screen reader was mispronouncing.

I found it by running a screen reader on that page for the first time and recording what it actually said.

So I’m not going to tell you my tooling is good. I am going to tell you it is honest about what it can’t see, and that’s a different claim.


So here is what I built, and what I think it is for

Section 6 of 12.

Englyn is a conformance standard for interfaces that are read by people and by agents, and it is public as of today.

That sentence is doing a lot of work, so let me take it apart.

It is a standard, not a tool. Fourteen normative requirements about properties a page has to have, written so that a stranger can satisfy them without adopting any of my process, my framework, or my opinions about how to build software. §2.1 says a conforming page must be achievable by hand-authored markup in a text editor, and that requirement is load-bearing: if a future version of this can’t be met that way, the version is wrong. There is nothing to install and nothing to buy.

It is data-englyn-* attributes on HTML you already have. Eleven of them. They say what a region is, what an action will do, whether it can be undone, whether a claim carries a receipt, and … the one I care most about … which consumer the annotation is for. No new elements. No runtime. Nothing in your production bundle.

And it is a set of instruments that are honest about their own blindness. Six test layers, each one able to see things the others structurally can’t, and three verdicts instead of two: CONFORMS, FAILS, and CANNOT-CHECK. That third verdict is the point. Automated tooling catches somewhere between thirty and fifty percent of accessibility problems by its own maintainers’ reckoning, which means a tool reporting “no violations” is telling you about itself as much as about your page. Englyn makes it say which.

What it is actually for

One payload, many renderings, and nobody gets the lesser version.

The same marked-up source serves a person using a screen reader, a person on a forty-cell braille display, a person whose attention is gone at four in the afternoon, an agent fetching the page directly, and an agent asking for the markdown twin instead. Not five sites. Not a main site and an accessible site that goes stale in a couple weeks. One document, read differently by different consumers, all of them entitled to the same meaning.

That’s the whole vision and it isn’t a new idea. It is what semantic markup was always supposed to do, and the reason it kept not happening is that the payoff went to people the budget didn’t prioritize. What is new is that the payoff now also goes to something with a budget attached, and I would rather use that than complain about it.

Why it has to be a standard rather than a library

Because a library serves whoever installs it, and the whole problem is the consumer you did not anticipate.

An agent hitting your page next year isn’t going to import your design system. A braille user isn’t running your framework. The only thing they can both rely on is the document, which means the contract has to live in the markup, be checkable from outside, and cost nothing to adopt. That’s a standard, and a standard’s success condition is that other people use it without talking to me.

And why it is deliberately unfinished

The top tier can’t be reached alone, by design. Bronze and Silver are claims about testing and I can assert those on my own. Gold requires recorded assistive-technology verification with paid community participation, and it can’t be self-certified by anyone, including me.

That tier isn’t written yet. Writing the requirements that govern disabled reviewers, without disabled reviewers in the room, would be the original problem in a new document. So that section is an invitation rather than a specification, and it is the part I most want help with.

What I have is a floor, a set of instruments, a report on my own failures, and an unfinished ceiling. That’s version 0.1.0, and it is enough to be useful and not enough to be trusted, which is exactly what it says on its first screen.


What is in the repository, and what each piece is for

Section 7 of 12.

Seventeen published paths. Here is what every one of them does, because a repository you have to reverse-engineer isn’t an invitation.

Read these three, in this order

spec/SPEC.md is the specification. Six sections. §0 is why it exists, §1 points at the vocabulary, §2 is the fourteen normative requirements, §3 is conformance and tiers, §4 is what a passing verdict does and doesn’t warrant, §5 is the limitations.

Start at §2 if you are here to implement, and §4 if you are here to decide whether to trust it. §4 is the liability section: what a CONFORMS claims, at which layer, and who is asserting it. Most standards leave that implicit. Leaving it implicit means your sharpest reader writes it for you.

spec/VOCABULARY.md is the normative source for every data-englyn-* attribute: the value spaces, which mark each one carries, whether it is MUST or SHOULD, and which consumer it serves. If a value isn’t in here, a conforming page doesn’t emit it. This file is the one that stops the vocabulary drifting, and it exists because it drifted: three published documents once defined six attributes while the site emitted eight.

spec/UNVERIFIED.md is the honesty file. Every assumption this project hasn’t verified, with what would settle each one. If you are looking for a reason to dismiss this, that file is the shortest route and I wrote it myself. I would rather you found the gap there than in production.

Then the tiers and the report

spec/TIERS.md defines Bronze and Silver, and declares Gold without defining it. It also carries the rule that took me longest to get right: the difference between a CANNOT-CHECK that blocks a tier and one that doesn’t. An instrument that never ran hasn’t passed. An instrument that ran, reached everything it could, and named what it couldn’t judge has told you the truth, and that’s a different thing.

reference/CONFORMANCE-REPORT.md is my own site’s report. Bronze, self-asserted, dated, against a named build. The longest section in it is everything the instruments couldn’t determine, and it publishes twenty-four linter failures with my reasoning for disagreeing rather than suppressing them. There is a clone-and-run block at the bottom. Running it against my own repository is what caught a false claim in an earlier draft of that very report.

Then the practical files

implementation/ENGLYN_QUICKSTART.md is the shortest path from nothing to a marked-up page. Start here if you want to see the shape before reading the specification.

implementation/ENGLYN_IMPLEMENTATION_GUIDE.md is the longer version: patterns, worked examples, and the mistakes that are easy to make.

testing/ENGLYN_TESTING_PROTOCOL.md describes the six layers and, more usefully, what each layer is blind to. That blindness is the design, not a gap.

testing/ENGLYN_ACCEPTANCE_CHECKLIST.md is what you tick against real output before you ship. It is deliberately boring.

testing/axe-integration-example/ is a worked example of wiring the automated audit into a build.

And the measurement files, which are optional

measurement/ENGLYN_MEASUREMENT_SCHEMA.md, englyn_schema.sql, and ENGLYN_TRANSPARENCY_REPORT_TEMPLATE.md are for anyone who wants to instrument conformance over time rather than at a point. Skip them entirely on a first pass. They matter at organizational scale and they are noise if you are marking up one page.

skills/englyn-accessible-page/scripts/spoken_number.py is a small utility for ambiguous digit strings. It exists because of a rule I got wrong twice: digits stay digits in an accessible name. Spelling numbers out reads fine to a speech synthesizer and eats cells on a braille display, which is forty to eighty characters of window over your whole page.

LICENSE, CHANGELOG.md, CONTRIBUTING.md

Specification text is CC-BY-4.0. The tooling is Apache-2.0 and lives in its own repository, because a patent grant is what somebody else’s legal review needs before they will run your code in their CI.

CONTRIBUTING.md is short and its first line is the important one: the most useful thing you can send is a failure.


How to actually do this to a site you own

Section 8 of 12.

Four stages. The first one is an afternoon and it is the only one I would insist on.

Stage 0 … Measure before you change anything

Run the checkers against your site as it is. Don’t mark anything up first.

You will get a number and a list of things the instruments couldn’t judge. That list is the useful output, not the number. It tells you where your page is ambiguous to something that can’t see it, which is usually not where you would have guessed.

Fire the controls first. npm run englyn:selftest before anything else. Every check has a must-fail fixture that has to fire and a must-not-fire fixture that has to stay quiet. A check whose control doesn’t fire is a permanent cannot-check wearing a pass. Mine once reported CONFORMS while scanning zero files.

Stage 1 … Regions and reading order

Tag the regions a briefing of your page would name. data-englyn-role and data-englyn-primitive on each, values from VOCABULARY.md.

Then check your DOM order against your reading order: title, narration, highest-priority content, supporting detail, actions. Visual arrangement is a rendering. Reading order is the payload. If CSS is doing the ordering, a consumer that can’t see the CSS gets a different document than you do.

This is also where you write the briefing region: a short sr-only section that says what is on the page and in what order. Put it where a reader chooses it, never first. Seventy-one point six percent of screen reader users navigate by heading, so the heading list has to carry the story on its own, and a briefing that interrupts before the heading list is available is a tax rather than a service.

Stage 2 … Consequences and reversibility

For every control that changes state: a data-englyn-consequence that says what will happen, mirrored in the accessible name or description.

That mirroring is the requirement I would fight for hardest. Every attribute this standard adds is invisible to a screen reader by default. Put your operation semantics in attributes and stop, and you have built a channel for agents and left the person using assistive technology with the worse page. Then the standard has made things worse for the people it was written for, which isn’t a hypothetical failure mode. It is the obvious one.

And declare reversibility rather than letting it be inferred. A consumer parsing English prose to decide whether something is safe can be accidentally wrong: correct wording, wrong pattern, wrong answer. Nobody accidentally declares an action reversible.

Stage 3 … Run the layers, in order, and read the verdict as measured

npm run englyn:selftest      # controls. if these do not fire, stop.
npm run build                # L1  static markup
npm run englyn:schema        # L2  schema, reads SOURCE not output
npm run a11y:html            # L1  HTML validity
npm run a11y:axe             # L3  axe-core in a real browser
npm run l4:keyboard          # L4  real keys, real focus

Serve the production build, not your dev server. Dev tooling injects elements that never ship. I measured a page that didn’t exist for three runs before noticing, and I only noticed because a screen reader read out four buttons that shouldn’t have been there.

Don’t tune a checker until it passes. If the verdict is FAILS, that’s the finding. Report it. Every defect worth having found here was found by an instrument that was allowed to fail.

Stage 4 … Listen. This is the one that matters.

Turn on a screen reader and go through your page. VoiceOver plus Control-Option-A on macOS reads from the cursor. Use the rotor, Control-Option-U, to walk the headings and the landmarks.

Write down what it actually says. Not what you expected. Not what the accessibility tree reports. What comes out of the speakers.

This is the layer that caught the only defect on my site that mattered, and every automated layer above it was green at the time. If your first listen finds nothing, that’s suspicious, not good.

Where the scores are, and why there is no single number

Section 9 of 12.

There is no Englyn score, deliberately.

A result is a tier (Bronze, Silver, Gold), bounded by a layer (L1 to L6), carrying a verdict (CONFORMS, FAILS, or CANNOT-CHECK), with everything undetermined published beside it. A single number would hide exactly the part worth reading.

And three verdicts rather than two, because automated tooling catches somewhere between thirty and fifty percent of accessibility issues by its own maintainers’ account. If half the problems are invisible to your tools, a tool that reports no violations has to be able to say “and here is what I couldn’t judge.”


What is wrong with this, on the first screen rather than the last

Section 10 of 12.

This is version 0.1.0. The limits ship in the same release as the claims, because a standard about verifiable claims that hid its own would be self-refuting.

No external review. No standards body. No independent audit. One person wrote the specification and the reference implementation, and then asserted the reference implementation conformant. That’s the weakest form of conformance claim there is, and §4 says so in those words.

One assistive technology tested. VoiceOver on WebKit. NVDA, JAWS, TalkBack, Narrator, and every braille display are untested. The one defect this layer found is WebKit-specific, so virtual-buffer readers may not even reproduce it.

Not every disabled reviewer ‘type’/condition has read this. The neurodivergent reading of the problem is first-hand, and I will stand behind that part: I am formally diagnosed, and the argument about cognitive load being a state rather than a trait is written from inside it. Screen reader experience isn’t mine. This document doesn’t speak for it.

The screen reader harness isn’t reproducible. Two runs of the same page returned sixteen headings and seventeen. The protocol requires identical results across two runs, so no run counts as a record yet. Silver is therefore not claimed, and the layer that has caught every defect worth catching is the layer I can’t yet run properly.

Gold is undefined. On purpose.

Which brings me to the ask

Section 11 of 12.

Gold requires recorded assistive-technology verification with paid community participation, and it can’t be self-certified by anyone, including me. You can’t reach the top tier of this standard without the community’s paid participation. That’s structural. It is in the test suite, not in a code of conduct where it is easy to ignore.

And it isn’t written yet, because writing the tier that governs disabled reviewers, without disabled reviewers, is just the original problem in a new document.

So:

If you build interfaces: clone it, run it against something you own, and send me the report. Especially if it fails. A FAILS from a stranger’s page is worth more to me than a hundred passes on my own machine, and I mean that operationally, not as a gesture. I have twenty-four published failures on my own site and I found the most useful one by having somebody else look.

If you use assistive technology: tell me where this is wrong. There are two specific questions in CONTRIBUTING.md that I can’t answer and you can, both about whether a pattern I chose actually serves you or just satisfies a linter. Your answer outranks my reasoning and I will change the code.

And on the unpaid part, plainly: there is no rate set and no budget in place, and I’m not going to dress that up. The invitation right now is unpaid and honestly framed. Paid review arrives when Gold is real. If that makes this the wrong ask for you today, that’s a completely reasonable answer, and I would rather you said so than felt obliged.

Two addresses, always cited together

Section 12 of 12.

waxandwires.com/englyn is the normative text. github.com/waxandwires/englyn is the source of record, and where to file against it.

Specification text is CC-BY-4.0. The checker is Apache-2.0, in its own repository.


Nothing about us without us is a demand, not a courtesy. This was written by somebody inside one part of that “us” and outside most of it. The right response to that isn’t to claim more. It is to leave the door open, and say which side of it you are standing on.

I built the ramp. I would like to know if it is the wrong shape.

Run-out groove

Four green lights, and a voice saying U-S. Etched by M.E., 2026.

Hidden track: the actual VoiceOver capture, 2026-08-17, trimmed to four seconds. Synthesized speech — a screen reader’s own voice, not this essay’s narrator. Transcript: “Heading level 2, what this buys US.”

Run-out groove

Run-out groove

Four green lights, and a voice saying U-S. Etched by M.E., 2026.

Hidden track: the actual VoiceOver capture, 2026-08-17, trimmed to four seconds. Synthesized speech — a screen reader’s own voice, not this essay’s narrator. Transcript: “Heading level 2, what this buys US.”


Liner Notes

The soundtrack to this essay

instruction → disorientation → presence isn't conformance → a label that lies → parts that fit

  1. “Fitter Happier” — Radiohead, OK Computer

  2. “A Forest” — The Cure, Seventeen Seconds

  3. “Don't Believe the Hype” — Public Enemy, It Takes a Nation of Millions to Hold Us Back

  4. “Maps” — Yeah Yeah Yeahs, Fever to Tell

  5. “The Egg” — Shiner, The Egg