Since July this website has had an accessibility statement. It is short, it lists its own shortcomings, and it admits that nobody from outside has looked at the site. This post shows what sits behind each point in the code. And why the statement needed a new version in September.
Why bother when nobody makes you
Germany's accessibility act, the BFSG, has applied since 28 June 2025. It implements the European Accessibility Act and covers certain products and certain services, among them e-commerce services. Section 2 no. 26 defines those as services offered through websites and apps and provided at a consumer's individual request, with a view to concluding a consumer contract.
No contract is concluded on this website. Some of my apps cost money, but people buy them in the App Store, not here. The Bundesfachstelle Barrierefreiheit, Germany's federal accessibility agency, says in its FAQ that purely informational websites are likely to lack that element of an individual request, and so are sites that merely advertise products. So in all likelihood the act does not cover this site. That is my reading, not legal advice. If you run a shop, have your own case checked.
I did it anyway. The benchmark is the Web Content Accessibility Guidelines (WCAG) 2.2 at level AA. The reason is unexciting: the site should work with a keyboard, a screen reader or heavy zoom. And retrofitting costs more than thinking about it from the start.
What is in place
The frame around every page
Header, navigation, footer and skip link come from the same file on every page. That is mostly about maintenance. For accessibility it means a mistake shows up everywhere. So does the fix.
- Skip link. The first thing on the page is "Skip to content". It sits off screen and slides in as soon as it gets keyboard focus. Keyboard users don't have to tab through the menu on every page (WCAG 2.4.1).
- Focus. Every focusable element gets an outline in the accent color through
:focus-visible(WCAG 2.4.7). Where a container would clip that outline, as with the gallery images, it is drawn on the inside. - State. The menu button reports through
aria-expandedwhether the navigation is open. Escape closes it and returns focus to the button. The light and dark toggle carriesaria-pressed, the current pagearia-current.
Language
The site is bilingual, and that matters for accessibility more than you might expect. A screen reader pronounces text in the language the code declares. Declare the wrong one and a German title comes out as gibberish.
- Every page declares its language on the
htmlelement. - The language switcher shows only "DE". That abbreviation is hidden from screen readers. In its place is an invisible "Deutsch", marked as German. What gets read out is a word you understand, pronounced correctly.
- A link that leads into the other language, such as the one from the English statement to the German original, carries a visible tag like "DE" and
hreflang. You know what you're getting before you click. - Blog posts cite sources under their original titles. A link can be followed by
{lang=de}, which gives itlangandhreflang. That serves WCAG 3.1.2, Language of Parts. The German sources below this post are marked up that way.
Tables, colors, motion
- Tables. The blog renderer puts
scope="col"on every header cell. That makes it unambiguous which column a header cell labels. - Contrast. The self-assessment computed the contrast of every color pair. Recomputed for this post, straight from the color values in the stylesheet: body text on the page background comes in at 13.3:1 in light mode and 14.3:1 in dark mode. Text in the main color is at its lowest on the highlighted source line of the gamebooks in light mode, at 10.7:1. The requirement is 4.5:1 (WCAG 1.4.3). The muted gray for secondary text is tighter in light mode: 4.9:1 on the page background, 4.5:1 on the slightly darker surfaces, such as the small tags on project cards. That passes, but only just.
- Accent color. As text on the light background, the accent color would only reach 4.35:1. Body and small text therefore get a darker variant at 5.8:1. The lighter one only appears at large sizes, where 3:1 is enough.
- Motion. Turn on "reduce motion" in your system settings and animations and transitions stop, and smooth scrolling goes away. The matching criterion, WCAG 2.3.3, is level AAA. That goes beyond my own target.
- Zoom. The site doesn't block zooming.
The gallery
The photo gallery has 125 pictures (as of September 2026), and each one has alt text. The German text lives in captions.json, the English in captions.en.json, both maintained by hand. A script checks them against the image folder and warns when an English description is missing. If one slips through anyway, the gallery shows the German text rather than nothing.
The thumbnails are real buttons, so Tab reaches them and Enter opens them. The enlarged view is a dialog. Focus stays trapped inside it, Escape closes it, and focus then goes back to the picture you came from.
The games
Sudoku in the browser, Logic Squares and the gamebooks build their interface in the browser. Their text therefore comes from string tables in the script, one per language. That includes any aria-label a script sets. On the two puzzles, messages like "Loading the puzzle" go into a status line marked up as a live region, so that a screen reader announces it on its own. On Logic Squares, the selected cell is also announced with its row, column and content.
The gamebooks
The four gamebooks run in a player that shows every choice as a button. The button's name is the text of the choice; the number in front of it is only there for the eye and hidden from screen readers. The first nine choices also work with the number keys, but only while focus is inside the game or on no element at all. If you are somewhere else on the page, a number key does nothing. After each choice, focus moves to the new passage.
The player sets the language on the game itself. "Brüder dunklen Rufes" only exists in German, so on the English page the book runs with lang="de", and a speech synthesizer reads it in German. Next to the game, the book's source sits in a panel that Tab reaches and the keyboard can scroll. Two books start with a choice, such as your weapon. That is a form with radio buttons, each group with a legend, each field with a label.
What is missing
In its version of 22 September 2026, the statement lists seven known limitations. As of September 2026, none of them has been fixed.
- Puzzle grids. Both boards announce themselves as a grid (
role="grid"), but the rows and cells that belong to that role are missing from the code. The statement calls this an incomplete ARIA structure. With a screen reader you therefore cannot move through the boards cell by cell. Logic Squares at least announces the selected cell; Sudoku does not. Both are fully operable by keyboard. - Keyboard shortcuts. Sudoku, Logic Squares and Pausensnake respond to single keys such as W, A, S and D anywhere on the page, and the puzzles also to N, H, P, C and the digits. That holds even when focus is nowhere near the board, and it can't be turned off. WCAG 2.1.4 requires that shortcuts made of a single character can be turned off or remapped, or only work while the component has focus. The reason: speech input users' dictation arrives as strings of letters, and people who tend to hit keys by accident trigger commands they didn't mean to. On top of that, the arrow keys don't scroll these pages; they always steer the game. The gamebooks are more careful, but not entirely: their number keys also work when no element has focus at all.
- Pausensnake. The game can be started and restarted, but not paused, and the snake moves at a fixed speed. For people who need more time, that is a barrier. The old version of the statement cited WCAG 2.2.2 for this. That doesn't fit: 2.2.2 is about movement that starts automatically, and the snake only sets off when someone presses a key or a button. Requiring that timing play no essential role is 2.2.3, at level AAA. The barrier remains all the same. A pause function is planned, but not built yet.
- Gamebooks. The player puts a
mainelement of its own into a page that already has one, so screen readers find two main landmarks there. Combat messages appear in status regions that are created anew with every step, and whether they get announced reliably is an open question. On The Intercept, and when a saved game is resumed, focus jumps into the game as soon as the page loads, past the introduction. The source panel carries no language attribute, even when it shows a file in the other language, such as the German source on the English page. And the highlight that follows the current position there is visual only. - Accent color in dark mode. On tinted surfaces the accent color only reaches 4.0:1, with 4.5:1 required. That affects the "New" label on the app cards and, while the mouse pointer is over them, the last column of the material table on the Maker page and the store link on app cards that have their own product page. Without the pointer it is 4.7:1 there.
- Alpine Drift. The game is embedded from itch.io. How accessible it is isn't up to me. A direct link to the original page sits next to it.
- Third-party content. Blog posts link to studies, PDFs and videos. I can't vouch for those.
How a statement goes stale
The first two gamebooks went live on 11 August, the fourth on 27 August. They were not in the statement until 22 September. Its line "no forms" stopped being true with the first book, because every one of them has a labeled drop-down for choosing the source file. Nothing gets submitted with it, but it is still a form control. The puzzle grid limitation was added to the statement on 8 August, and the review date stayed at 26 July.
The September review turned up more than the gamebooks: the keyboard shortcuts, the accent color in dark mode, the wrong reasoning for Pausensnake. The figure "above 13:1" for body text did not hold on every surface; for text in the main color it now says "at least 10.7:1". And "partially conformant" is not the term the EU model statement uses. A statement describes the website on a particular day. Every new page is a reason to open it up again.
What has not been checked
The statement rests on a self-assessment from 18 July 2026. It covered markup, stylesheets and scripts against the level AA success criteria, plus a computed contrast check. The statement was reviewed on 26 July and most recently on 22 September 2026, again on the code. No independent external audit has taken place. The statement mentions no testing with screen readers or other assistive technology, and this post doesn't claim any either.
The statement calls the site "partially compliant" with the requirements. That term comes from the European Commission's model accessibility statement, which distinguishes between fully, partially and not compliant. The code tells you whether an attribute is there. It doesn't tell you whether the site works well with a particular screen reader in a particular browser. The people who use it that way know that.
When something doesn't work
That is why the accessibility statement has a contact address. It helps to name the page, the barrier and, if you like, the assistive technology you use. I usually reply within a week. Every report is a test I could not have run on my own.
Sources
- W3C: Web Content Accessibility Guidelines (WCAG) 2.2 - the benchmark for this website, success criteria 1.3.1, 1.4.3, 2.1.4, 2.2.2, 2.2.3, 2.3.3, 2.4.1, 2.4.7 and 3.1.2 with their levels
- W3C: Understanding Success Criterion 2.1.4: Character Key Shortcuts - why single-character shortcuts get in the way of speech input users
- W3C: Understanding Success Criterion 2.2.2: Pause, Stop, Hide - what "starts automatically" means
- Austrian Research Promotion Agency (FFG), digitalbarrierefrei.at: Model statement in English - template based on Implementing Decision (EU) 2018/1523, with the levels fully, partially and not compliant
- Federal Ministry of Justice and Federal Office of Justice: Barrierefreiheitsstärkungsgesetz (BFSG) - the act, with its scope in section 1 and definitions in section 2 (German)
- Bundesfachstelle Barrierefreiheit: FAQ zum Barrierefreiheitsstärkungsgesetz (BFSG) - in force since 28 June 2025, how purely informational and promotional websites are treated (German)
- MDN Web Docs: prefers-reduced-motion - the system's reduce motion setting in CSS
- MDN Web Docs: lang HTML global attribute - language markup and correct pronunciation in screen readers
- MDN Web Docs: ARIA: aria-live attribute - how the games' status messages get announced
- MDN Web Docs: ARIA: grid role - which rows and cells an element with
role="grid"has to contain