NASE Accessibility
A full accessibility audit and redesign of the NASE platform for visually impaired users. 23 issues found, categorised by WCAG 2.1 severity, with redesigned components and an AI-powered contrast analysis pipeline.
NASE Accessibility started as an HCI course project, but quickly became something more personal. I audited the NASE platform — a digital tool used by visually impaired students in Malaysia.
The goal: find every barrier that prevents a visually impaired user from navigating the platform independently, categorise each issue by WCAG 2.1 severity, and produce a redesigned prototype that passes AA compliance.
23 issues identified across 5 pages of the NASE platform, categorised by WCAG 2.1 severity:
alt attributes. 14 decorative images and 3 informational images lack alt text — screen readers skip or misread them.<label> elements — screen readers read placeholder text only, which disappears on input focus.role="presentation"Manual contrast checking is slow. I built a Python pipeline using OpenCV and TensorFlow to automatically detect text regions, extract foreground/background colours, and calculate contrast ratios across every page screenshot.
L = 0.2126 × R + 0.7152 × G + 0.0722 × B
(where R, G, B are linearised sRGB channels in [0, 1])
contrast_ratio = (L1 + 0.05) / (L2 + 0.05)
(L1 = lighter color, L2 = darker color)
WCAG AA requires ratio ≥ 4.5:1 (normal text)
WCAG AAA requires ratio ≥ 7:1 (normal text)The 0.2126 / 0.7152 / 0.0722 weights aren't arbitrary — they come from the relative luminance the human eye perceives per channel, with green contributing far more to perceived brightness than blue. The "+0.05" offset in the ratio formula accounts for ambient screen glow so the formula never divides by something close to zero on a true black background. Run against every text/background pair on the site, this is what decided which color combinations were usable before a single line of the design was finalised.
# Body text #374151 on background #FFFFFF
R,G,B (linearised) for #374151 ≈ 0.035, 0.054, 0.075
L1 = 0.2126(0.035) + 0.7152(0.054) + 0.0722(0.075)
≈ 0.052
R,G,B (linearised) for #FFFFFF = 1, 1, 1
L2 = 1.0
contrast_ratio = (1.0 + 0.05) / (0.052 + 0.05)
≈ 10.3 : 1
→ passes WCAG AAA (≥ 7:1) for normal text