Liubov Tsebekova

02 · DesignGrounds

A design school where every claim has a source

Design knowledge is scattered across courses, blogs, books and guidelines, and the link between an idea, its source, the interface decision it implies and any way of checking you understood it is usually lost. Over time, understanding turns into a collection of bookmarks.

Scale
113 built pages · 12 learning tracks · 52 open lessons · 120 glossary terms · 79 sourced questions across 12 banks · 13 interactive demo types · 67-book shelf
Stack
Astro 7 + TypeScript · 9 typed content collections · zero client-side framework runtime · vanilla-JS islands · Pagefind search
Timeline
Solo. Designed, written and built in eight weeks
Quality bar
WCAG 2.2 AA · contrast checked programmatically · CSP, HSTS and a security self-audit before launch
Built with
Claude Code on the repetitive plumbing. Curriculum, content model, writing and every design decision mine

What this case doesn’t claim. A self-audit finds problems. It does not measure users. Nobody outside has been observed using this yet, so everything here is directional evidence plus technical verification. The first evaluative study is designed — unmoderated, n=10, desktop and mobile, behaviour-screened, four tasks framed as goal plus motivation, SEQ after each, success criteria fixed in advance — and it has not been run.

Architecture before pixels

Two weeks went into structure before a single visual decision: twelve learning tracks, six core flows, and the content model — lesson → term → pattern → question → study — expressed as Astro content collections with schemas validated at build.

That let me enforce one editorial rule mechanically rather than by discipline: a lesson ships together with its glossary terms and two or three questions, or it does not ship. It becomes impossible to publish a lesson that introduces vocabulary it never defines, or a quiz that tests something nobody taught.

The loop the model produces is Learn, Reference, Practice. A lesson explains the topic. A term, pattern, book or study lets you come back to it mid-task without re-reading anything. A question checks whether it stuck — and a wrong answer returns an explanation, a link to the lesson that covers it, and an entry in Weak topics.

This is the decision that let the project survive its own growth. At 113 pages the thing is still coherent, and it is coherent because the schema will not let it drift.

The first version was competent, and wrong

v1 proved the information architecture worked. Visually it used the standard course-catalogue pattern: a large promise in the hero, a row of counters, an even grid of cards, every content type carrying the same weight.

The flaw took a while to name. The platform was talking about an evidence-based method and never showing the mechanism on the first screen. A visitor had to take the claim on trust and open a lesson to find out whether it was true — which is exactly the behaviour the product exists to argue against.

The second direction came from the name. Grounds — territory, route, field marks, coordinates, accumulated knowledge. Field guide plus evidence atlas. The hero now runs the actual chain live, evidence → principle → pattern → practice → decision, with a real primary source at one end and a working interface at the other, so you can see how the platform thinks before you commit to anything.

A second decision followed: content type determines surface. Forest greens carry evidence, acid marks action and progress, clay does wayfinding — with a separate darker token for clay text, because the raw clay fails AA and a decorative colour has no business carrying information.

The product architecture did not change in the redesign. What changed is what the system looks like it is.

Teaching by breaking things

Thirteen kinds of in-lesson demo, built because some rules cannot be taught in a paragraph. A live WCAG contrast slider where the badges flip as you drag past 4.5:1. A focus-trap modal you can try to tab out of. A validation-timing toy that shows why on-blur beats on-keystroke. A component-state switcher. An information-scent game.

The bet is that you learn a rule properly by breaking it once, somewhere breaking it is free. It is also the only honest way to teach accessibility — a screenshot of a contrast failure is a claim; a slider that fails in your hands is evidence.

Pointing the curriculum at itself

The site teaches research methods, so running them on the site was the only defensible option: a heuristic audit, three personas with jobs-to-be-done, journey maps, a registry of twenty frictions, and a gap map of routes that did not exist.

The finding that mattered: v1 was much stronger for a first visit than a second. Everything had been designed for arrival and nothing for return. Someone coming back after a week had to rebuild their own context before they could learn anything — which, for a product about retaining knowledge, is close to a contradiction.

Eleven fixes shipped as one release rather than dribbling out: Continue where you left off, progress on the cards, completion states with a next step, quiz errors linking to the lessons that teach them, Weak topics, My progress, an export/import sync code, a Start here self-assessment, mobile navigation collapsed into a menu, a Cmd/Ctrl+K search overlay that keeps your current context, and term popovers.

Worth being precise about what that is: a self-audit finds problems that a designer can see. It does not tell you what a stranger does. Those are different claims and I keep them separate.

Security, because I ship my own code

Launch headers: Content-Security-Policy, HSTS, nosniff, frame denial, permissions lockdown. Two honest compromises inside that CSP — unsafe-inline in script-src, because Astro inlines small island scripts, and wasm-unsafe-eval, because Pagefind’s search runs on WebAssembly. Both are weaknesses I can name and justify, which is better than a policy that looks strict in a screenshot and was quietly relaxed to make the build pass.

The robots file lets normal search engines through and blocks the AI-training and bulk-scraping crawlers by name.

The bug I care about was in a feature I was pleased with. Because there are no accounts, progress moves between devices as a code you copy from one browser and paste into another — a base64 blob that gets decoded, stored, and then rendered into the page. Which is to say: text supplied by whoever wrote the code, persisted, then treated as markup. That is the exact shape of a stored cross-site-scripting vector, and I had built it into the one feature designed to accept a payload from somewhere else.

It is fixed. Every interpolation goes through an escaper; every imported field goes through a length-capped, type-checked reader that will not accept a value it does not recognise. I am not a security engineer. I do think a designer who ships their own code owes their own work the suspicion they would give a stranger’s.

The stopping rule

What is verified here is technical: contrast per pair, every search result URL checked against the production output, glossary anchors generated by one shared helper, broken-link and anchor passes, keyboard and mobile walkthroughs, empty and error states, content counters, a clean production build with no dev messages leaking into the interface.

What is not verified is whether anyone learns anything. So the first evaluative study is fully specified and waiting: unmoderated, n=10, desktop and mobile, behaviour-screened recruiting, four tasks written as goal plus motivation, SEQ after each, success criteria fixed before anyone runs it.

And a rule I committed to in advance, which is the part I would defend hardest: if fewer than eight of the ten participants can find their own way in, work on new content freezes until the information architecture is fixed and re-tested at n=5.

Writing more lessons is the fun part and the easy way to look productive. Deciding beforehand what result would make me stop is the only way I know to keep a self-directed project honest, because in the moment I will always be able to argue that the test was unfair.