VHPUNK $99 LIFETIME
★ METHODOLOGY · OPEN SOURCE · 2026-06-25

The scanner is one file. The audit data is a CSV. Re-run it yourself.

VHPunk is a deterministic static analysis. Three rules. No AI, no ML, no heuristics. Same input → same output, every time. Bring your own codebase.

The three rules

What gets scanned

The scanner recursively walks a directory and parses these file types:

Skipped by default: node_modules, dist, build, .next, .cache.

Scoring

Score = max(40, 100 - findings × 8). Floor at 40 so a heavily-traveled site doesn't bottom out and lose all signal. A clean codebase = 100. Five findings = 60. Twenty findings = 40 (the floor).

Run it yourself · 60 seconds

$ npx --yes @radioart/vhpunk ./src

# scan a single file
$ npx --yes @radioart/vhpunk ./src/HeroSection.tsx

# machine-readable output (CI gates, dashboards)
$ npx --yes @radioart/vhpunk ./src --format=json

# GitHub Actions annotations
$ npx --yes @radioart/vhpunk ./src --format=github

Free for any project, any size, any commercial use. The --fix flag (in-place patches) requires a $99 lifetime license — pay once, use forever.

The receipts

Below is the actual scanner source and the raw audit data we ran for this writeup. Click to download. The CSV is small enough to read inline; the scanner is one file, ~250 lines, MIT-licensed.

scanner.js
The actual VHPunk scanner source. ESM module exporting scan(targetPath). Returns an array of findings. ~250 lines, MIT.
results.csv
Raw scan results: 8 famous homepages + 3 known-state fixtures. Score, finding count, scope, timestamp, scope-of-scan note. Reproducible.

What the audit found · honest read

target,scope,findings,score "apple.com (homepage HTML)","html-only",0,100 "figma.com (homepage HTML)","html-only",1,92 "google.com (homepage HTML)","html-only",0,100 "linear.app (homepage HTML)","html-only",0,100 "notion.so (homepage HTML)","html-only",0,100 "stripe.com (homepage HTML)","html-only",0,100 "vercel.com (homepage HTML)","html-only",0,100 "youtube.com (homepage HTML)","html-only",0,100 "VHPunk fixture: buggy-landing.html","fixture",3,76 "VHPunk fixture: buggy-react.jsx","fixture",2,84 "VHPunk fixture: clean-landing.html","fixture",0,100

Honest read. Most modern marketing-site homepages no longer hardcode 100vh inline — the rendered HTML the edge serves is mostly clean. That's because the bug has migrated into component bundles. The hero gets cut off behind iOS Safari's URL bar in production because of a single height: 100vh in a React/Vue/Svelte component that ships in the client JS bundle, not because the marketing site's <style> block has it.

This is exactly why VHPunk is a source-code scanner, not a rendered-HTML scanner. The free in-browser scan at /scan catches what's in the rendered HTML; npx @radioart/vhpunk catches what's in your source tree, which is where the bugs actually live.

The fixtures at the bottom of the CSV (buggy-landing.html, buggy-react.jsx, clean-landing.html) prove the scanner detects what it claims to detect — known-state inputs, predictable outputs.

What VHPunk does not scan

Methodology updated 2026-06-25 12:08 CDT. The scanner is MIT-licensed. The audit data is CC0. The voice is brash because the gap is real — every iPhone since 2016 has supported dvh-equivalent behavior and the spec for dvh/svh/lvh shipped in Safari 16 in 2023. We're three years past the fix and the trap is still in production. ← back to vhpunk.pages.dev