Skip to content

Audit the app itself: fix accessibility defects and make forks resolve their own origin - #346

Merged
singhharsh1708 merged 2 commits into
mainfrom
fix/fork-safe-origin
Aug 27, 2026
Merged

Audit the app itself: fix accessibility defects and make forks resolve their own origin#346
singhharsh1708 merged 2 commits into
mainfrom
fix/fork-safe-origin

Conversation

@singhharsh1708

Copy link
Copy Markdown
Owner

Two things I flagged as unfinished. The deliverables were measured and fixed earlier; the app itself never was, and now that anyone can fork it, several things still named your deployment.

The accessibility audit

Ran Lighthouse against all nine public pages of the built app. Every one had real failures.

One token explained 31 of them. --primary is both a button fill and accent text. At oklch(0.52 0.22 290) it measures 3.18:1 on the card surface — below the 4.5:1 floor. It can't just be lightened: white on that same colour as a fill measures 6.11:1 and passes, so raising lightness would break that instead. Accent text now has its own --primary-ink at oklch(0.66 0.18 290)5.87:1 worst case — and the 48 text-primary usages point at it. Fills and borders untouched.

@tailwindcss/typography was never installed. All three legal pages carried prose prose-invert prose-sm, so every one of those classes was inert and the pages rendered as unstyled markup. Now a real dependency and registered.

The decorative numerals behind the pipeline cards were flagged at 1.06:1. aria-hidden doesn't exempt them, and rightly so — a low-vision sighted reader still sees them. I measured what passing would take: roughly white/40, which is no longer a faint watermark. They're pure decoration under WCAG 1.4.3, so they're drawn as generated content rather than text, which is how that's expressed in a way a checker agrees with. Verified in isolation that the pseudo-element still renders.

Also: the editor had no <main> landmark, an unnamed add-section button and an unlabelled site-name input; a responsive duplicate of "View all presets" hid its own label at one breakpoint leaving the anchor unnamed; the sponsor button was white on pink-500 at 3.53:1, now pink-600 at 4.60:1.

<Analytics /> was mounted unconditionally. The insights script only exists when Vercel serves it, so every self-hosted or local run logged a 404 plus a strict-MIME error on every page — noise for exactly the people this project is now aimed at. Gated on the deploy environment.

Measured, before → after

page accessibility best practices
home 92 → 100 96 → 100
gallery 96 → 100 96 → 100
editor 89 → 100 96 → 100
contact 96 → 100 96 → 100
about 96 → 100 96 → 100

Forks resolve their own origin

A fork's exported READMEs credited your deployment, its social card printed your domain, and its canonical URLs pointed at you. siteUrl now resolves SITE_URL → Vercel's own env → fallback, the social card prints whatever that resolves to, and an exported README credits window.location.origin. PRODUCTION_URL is gone.

Verified

  • tsc, eslint, next build clean; suite 213 → 223.
  • The contrast tests compute ratios from the tokens rather than asserting hex strings, so a regression fails with the measured number — proven by reverting the token, which fails with accent text on the page surface is 3.38:1.
  • Two tests pin fork-safety: nothing a fork ships may contain your deployment URL, and the origin must be read from config before any fallback.

Not changed: /create and /editor are disallowed in robots.txt, which caps their SEO score at 63. That's deliberate — they're the tool, not marketing pages — so I left it.

Now that anyone can fork and self-host this, several things still named the
original deployment. A fork's exported READMEs credited it, its social card
printed its domain, and its canonical URLs and sitemap pointed at it.

siteUrl now resolves SITE_URL, then whatever Vercel reports
(VERCEL_PROJECT_PRODUCTION_URL or VERCEL_URL), and only then falls back — so a
fork publishes its own URLs with nothing configured. The social card prints
whatever that resolves to, and the README inside an exported ZIP credits
window.location.origin, which is the deployment the person actually used.

Removes the PRODUCTION_URL constant, whose whole purpose was to name one host,
and makes the README's origin argument required so a caller cannot silently fall
back to someone else's.

Two tests pin it: nothing a fork ships may contain the maintainer's deployment
URL, and the origin must be read from configuration before any fallback.
The exported and published sites were measured and fixed earlier; the app itself
never was. Auditing all nine public pages with Lighthouse found real failures on
every one of them.

The largest was a single token. --primary serves as both a button fill and as
accent text, and at oklch(0.52 0.22 290) it measures 3.18:1 on the card surface -
below the 4.5:1 floor - which failed 31 nodes across the app. It cannot simply be
lightened: white on that same colour as a fill measures 6.11:1 and passes, and
raising the lightness would break that instead. So accent text gets its own
--primary-ink at oklch(0.66 0.18 290), measured at 5.87:1 worst case, and the 48
text-primary usages now point at it. Fills and borders are untouched.

The three legal pages carried `prose prose-invert prose-sm` while
@tailwindcss/typography was never installed, so every one of those classes was
inert and the pages rendered as unstyled markup. The plugin is now a real
dependency and registered.

The decorative numerals behind the pipeline and feature cards were flagged at
1.06:1. aria-hidden does not exempt them, and rightly so: a low-vision sighted
reader still sees them. Reaching the 3:1 large-text floor would need about
white/40, which is no longer a faint watermark. They are pure decoration under
WCAG 1.4.3, so they are drawn as generated content instead of text, which is how
that is expressed in a way a checker agrees with.

Also fixed: the editor had no main landmark, an unnamed icon-only add-section
button and an unlabelled site-name input; a responsive duplicate of the "View all
presets" link hid its own label at one breakpoint and left the anchor unnamed;
and the sponsor button was white on pink-500 at 3.53:1, now pink-600 at 4.60:1.

<Analytics /> was mounted unconditionally. The insights script only exists when
Vercel serves it, so every self-hosted or local run logged a 404 and a strict
MIME-type error on every page - noise for exactly the people this project is now
aimed at. It is gated on the deploy environment.

Measured before and after, on the built app:

  home       acce  92 -> 100   best  96 -> 100
  gallery    acce  96 -> 100   best  96 -> 100
  editor     acce  89 -> 100   best  96 -> 100
  contact    acce  96 -> 100   best  96 -> 100
  about      acce  96 -> 100   best  96 -> 100

The contrast tests compute the ratios from the tokens rather than asserting a
hex string, so they fail with the measured value when a colour regresses.
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
scrollcraft Ready Ready Preview Aug 27, 2026 11:14am

@singhharsh1708
singhharsh1708 merged commit c333f7c into main Aug 27, 2026
3 checks passed
@singhharsh1708
singhharsh1708 deleted the fix/fork-safe-origin branch August 27, 2026 11:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant