← Back to work

Live SaaS · Designed & built

AccessSpark: the accessibility platform I designed and built end to end

A live auditing platform that tests the modern web the way real users meet it, in a real browser, behind logins, and produces a VPAT from what it actually measured.

Role
Product, UX, architecture, and build
Timeline
Concept 2025, launched March 2026 · live
Tools
Full stack, design system, marketing
Focus
Product design, accessibility, AI
app.accessspark.io · dashboard
AccessSpark dashboard The AccessSpark dashboard showing sites monitored, total scans, average score, open issues, a score-trend chart, category averages, and per-site health cards. AccessSpark Dashboard Sites All scans Scheduled Settings MONITORED SITES example.com96 example.org88 shop.example91 docs.example84 S Sam Carter PRO Audit a URL… Audit Sites monitored8 Total scans142 Avg score91 Open issues37 Score trends Category averages Accessibility96 SEO90 Security84 Performance92 Site health 96 example.com12 issues 88 example.org31 issues 91 shop.example9 issues

Why I built it

A blind friend couldn't get through a site that an automated checker rated clean. The scanner said everything passed; a real person using a screen reader was stuck. That gap, between what tools measure and what people experience, is the whole reason AccessSpark exists.

I built it to audit the web the way it actually ships today: single-page apps, React dashboards, pages behind a login, sites with bot protection that static scanners never reach. I built it for my own consulting work first, then turned it into a product.

The core decision: audit the rendered page, in a real browser

Static scanners read the HTML a server ships. That is exactly what failed my friend: the markup parsed clean while the rendered page was unusable. AccessSpark loads every page in headless Chrome and audits the fully rendered DOM, the same thing a screen reader meets. It costs more in compute and in engineering than parsing static HTML, and it is the only way to catch the single-page apps, React dashboards, and login-gated pages where the real failures live. Choosing the cheaper static approach would have rebuilt the exact tool that rated the broken site as passing.

What I designed and built

End to end: product vision, UX, the design system, the architecture, billing, docs, and the marketing site. It reaches users through four surfaces, each suited to a different moment in a team's workflow.

Web app
Audit and monitor

Run audits, manage multi-page crawls, track trends, and export reports.

Chrome extension
Behind the login

Audit authenticated and staging pages using your own session, one click.

CLI
In your pipeline

Drop into CI/CD and fail a build on an accessibility regression.

MCP server
For AI agents

Let an AI assistant run audits inline, right in the conversation.

Flint: the system underneath

Every surface above stands on one design system. I named it Flint. It is the source the brands are struck from, and it runs AccessSpark and this portfolio today, with Inner Spark Media migrating onto it next.

Flint is one token source for color, type, spacing, radius, control sizing, and icon and target-size minimums. Components read from semantic intent tokens rather than raw values, so a button or an input cannot drift between products, and the same tokens drive light and dark. Accessibility lives in the primitives, not a later pass: color pairs are contrast-checked, and minimum target sizes and focus styles are tokens, so anything built on Flint inherits them.

Flint design tokens The Flint foundations: a contrast-checked color palette, a type scale, spacing and radius scales, components in default, focus, and disabled states, and accessibility defaults including minimum target size, visible focus, and shared light and dark tokens. FLINT · DESIGN TOKENS COLOR · CONTRAST-CHECKED Navy15.8:1 Blue5.7:1 Skyaccent Slatetext Success Warning Danger Surface Primitive ramps plus semantic intent tokens. TYPE SCALE Display32 · 800 Heading22 · 700 Body text16 · 400 Caption13 · 500 Open Sans across every identity. SPACING 4816243248 RADIUS xssmmdlgpill COMPONENTS & STATES Button default Button focus Button disabled Input field input Pass Warn Fail status, by label and color ACCESSIBLE BY DEFAULT Contrast pairs built into the tokens 44px minimum target size Visible focus on every control Light and dark from one set of tokens Light Dark
Flint foundations: contrast-checked color, type, spacing and radius scales, and components that carry their own focus and target-size rules.

One token source

Color, type, space, radius, control, and target size in a single place.

Semantic by default

Components use intent tokens, so they cannot drift between products.

Accessible primitives

Contrast, focus, and minimum target size are built into the tokens.

Themed, not forked

One foundation; each identity is a brand layer on top.

What it does

One run gives the whole picture. Accessibility against WCAG 2.0 through 2.2 with axe-core plus my own checks, run against the fully rendered page, alongside SEO, security, and performance. Then it goes further than a list of violations.

app.accessspark.io · audit report
AccessSpark audit report An AccessSpark audit report with category tabs, score columns for accessibility, SEO, security, performance and interaction, and an issue card showing the WCAG criterion, a suggested fix, a learned fix, and the offending code. All Accessibility SEO Security Performance Interaction Manual Checks Trends PDF VPAT AI Fix All Render mode: Static HTML · 198ms ACCESSIBILITY 92 2 Fail · 6 Warn SEO 96 1 Warn · 5 Info SECURITY 84 4 Warn PERFORMANCE 90 1 Warn · 3 Info INTERACTION N/A Requires JS rendering SERIOUS Buttons should be links for screen-reader navigation 8 instances WCAG 2.4.5 · AA Fix: convert the <button> to an <a href> so it appears in the screen-reader links list. Learned fix: use <a href> with scroll-margin-top instead of e.preventDefault(). <button>Menu</button>

Real-browser rendering

Headless Chrome loads the real DOM, so SPAs and dynamic content get caught.

AI fix, one or all

Code-level remediation per element, written for the engineers who ship it.

Real VPAT 2.5

Every criterion derived from detected issues; untested items marked honestly.

Continuous monitoring

Crawl whole sites and track scores over 7, 30, and 90-day windows.

The outcome

AccessSpark is live and in real use. It also audits this very portfolio on every release, which is why the accessibility claim in the footer is measured, not asserted.

90+
Accessibility rules across WCAG 2.0, 2.1, and 2.2
165+
Audits run across 35 monitored sites
VPAT 2.5
Conformance reports generated from real results

What I'd carry forward

Building the whole thing, product, system, and code, made the lesson concrete: accessibility has to live in the primitives, early, rather than in a final audit. Flint bakes contrast, focus, and target size into the tokens, so anything built on it inherits them, and that is the same move I bring to an enterprise team: make the accessible thing the default so conformance stops being a cleanup pass. It also set how I think work should be judged. AccessSpark audits this portfolio on every release and produces a real audit and VPAT anyone can open, so the claim is checkable rather than asserted.

See the real output

Both files are genuine output from AccessSpark, so you can judge the work rather than take my word for it.

Next case studyD&B Hoovers