How it's built

This site was designed and built by a one-person studio using AI-assisted tooling, reviewed and directed by Karan.

That means AI tools drafted much of the code and copy to a written brief. Karan set the direction, made the decisions and reviewed the result. The rules the site is held to (no trackers, no third-party requests, strict security headers, accessibility, honest copy) are checked by automated tests.

Stack

  • Static HTML, generated by a small Python build script that uses only the standard library.
  • Custom CSS and JavaScript written for this site. No frameworks, no libraries, no npm packages shipped to your browser.
  • Self-hosted font: JetBrains Mono, subset, under the SIL Open Font License. Body text uses your system font.
  • Hosting: Cloudflare Pages, with one small Pages Function for the contact and project-brief forms.
  • Zero third-party requests. No CDNs, analytics, web fonts from elsewhere, or embeds.

Build pipeline

Markdown + JSON + templates (src/)
        │
        ▼
build.py  (Python standard library only)
  ├─ Markdown → HTML (escaped by default)
  ├─ pages, blog, feed, sitemap, search index
  ├─ _headers, security.txt (Expires = build date + 360 days)
  └─ fingerprinted CSS / JS / fonts
        │
        ▼
public/  ──►  tests (unit, end-to-end, accessibility, performance)
        │
        ▼
Cloudflare Pages (static files + /api/* Function)

The numbers

The build-time figures in the first table are computed by build.py each time the site is built. The test and Lighthouse figures come from the evidence files saved by each test run. Each table says when it was recorded. Anything without a passing, recorded result is left out.

Every figure here is measured, not claimed.

Measured by build.py when this page was built
MeasureValue
Pages25
Tools7
Posts4
JavaScript dependencies shipped0
Total site weight2134 KB across 106 files

Evidence summaries live in the repository under docs/evidence/.

Tests

Recorded on 14 Oct 2026. Whole run: 291 checks passed, 0 failed, 2 skipped (every skip is environmental and listed in the repository report).

SuiteTestsResult
Build script (build.py)99All passed
Contact and project-brief function65All passed
Effects controller15All passed
Contact form abuse cases13All passed
Tools43All passed

Lighthouse

Lab data from a local server, not field data. Recorded 14 Oct 2026 with Lighthouse 13.5.0 on 28 pages. Mobile uses Lighthouse's simulated throttling; desktop uses its desktop preset. Where two numbers are shown they are mobile / desktop. Scores are out of 100; LCP and TBT are in milliseconds.

PagePerformance (mobile)Performance (desktop)AccessibilityBest practicesSEOLCP, mobileCLS, mobileTBT, mobile
/404.html9410010010066286200
/about/94100100100100285900
/accessibility/9410010010010028670109
/blog/94100981001002858018
/blog/personal-security-setup-in-a-weekend/941001001001002859040
/blog/securing-a-small-business-website/9110010010092 / 10018010281
/blog/securing-a-static-site-on-cloudflare-pages/9010010010010030450205
/blog/web-app-pwa-or-native-app/931001001001003046064
/contact/941001001001002860043
/demos/9310010010010030130104
/how-its-built/941001001001002859077
/8810010010010019510.005428
/personal-security/941001001001002860048
/privacy/94100100100100286700
/projects/94100100100100286000
/search/941001001006619510248
/services/8810010010010019510426
/start/941001001001002924079
/styleguide/94100100100662864057
/tools/csp-analyzer/9410098100100286000
/tools/encoder/94100100100100286100
/tools/hash/941009810010021010257
/tools/9310010010010028590130
/tools/jwt-decoder/94100100100100286000
/tools/password/931001001001003014037
/tools/security-headers/881009910010021010414
/tools/security-txt/9499100100100286000
/trust/9310010010010028610141

The Trust page lists the security headers the site sends, generated from the same configuration file that is deployed.

Effects, and how they step down

The site is designed so that motion is a layer on top of ordinary pages, never a requirement. Every page can be read and navigated with JavaScript turned off and with reduced motion on.

Each effect has its own on/off switch in the site's configuration. An effect is switched on only after its tests pass.

When effects are on, a controller picks a level for your device: Full, Lite or Off. It steps down if animation runs slowly, and pauses effects when the tab is hidden. The list below is generated from the site's effect switches, so it always matches what is deployed.

  • Controller (on): picks Full, Lite or Off for your device. Without it, no effect code loads and pages are plain.
  • Hero (off): the animated panel beside the home page heading. Falls back to static text.
  • Scramble (on): animated decoding of headings. Headings are plain text.
  • Command palette (on): keyboard search. Use the menu and the search page.
  • Terminal (on): a command line for moving around the site. Use the menu.
  • View transitions (on): smooth changes between pages in supporting browsers. Falls back to normal page loads.
  • Proof strip (on): the measured facts under the home page heading animate in. Falls back to the same figures as static text.
  • Storytelling (on): sections reveal as you scroll. Falls back to everything visible at once.
  • Bento grid (on): hover and focus detail on the home page tiles. Falls back to plain tiles.
  • Polish (on): small extra touches such as a reading progress bar.

No effect may flash more than three times a second, every moving effect must be possible to pause or turn off, and the site plays no audio.

Security

The site sends a strict Content-Security-Policy: scripts, styles, fonts and workers only from this origin, no inline scripts or styles, no eval. Effects are held to the same rules. The full header list is on the Trust page, and the setup is explained in Securing a static site on Cloudflare Pages.

Accessibility

The target is WCAG 2.2 AA in every theme and accent combination, checked with automated tests. See the accessibility statement.