Case study · This website

How this site is built

A static site with no framework, no server code and no trackers, hardened with the same discipline I use at work: strict headers, safe fallbacks, and everything verifiable.

  • HTML5
  • CSS custom properties
  • JavaScript modules
  • three.js
  • GSAP ScrollTrigger
  • Apache/LiteSpeed .htaccess

Role: Design, build, and hosting

The challenge

What needed fixing

A portfolio should load fast on a phone, read well without JavaScript, respect people who prefer reduced motion, and not leak anything: no third-party scripts, no cookies, no analytics. It also had to be simple to deploy: a zip uploaded to shared hosting, with no build step.

My approach

What I did, in order

  1. Static files only

    Every page is plain HTML with real text, three CSS files and a few small JavaScript modules. No framework, no server-side code, no database. Fonts are self-hosted so nothing is fetched from third parties.

  2. Background scene that never blocks the page

    The particle scene (one three.js Points object with a custom shader, morphing between formations as you scroll) is lazy-loaded after the page is interactive. If motion is reduced, WebGL2 is unavailable, data saver is on, or the device is weak, a still image shows instead, and the text never waits for it.

  3. Strict Content Security Policy

    Scripts, styles, fonts and images are same-origin only. There is no unsafe-inline: the two inline scripts (theme bootstrap and the import map) are allowed by SHA-256 hashes. frame-ancestors is none, base-uri and form-action are self.

  4. Transport and browser hardening

    HTTPS is forced with a single 301 (www redirects to the apex), HSTS is set for a year with subdomains, plus X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy and Cross-Origin-Opener-Policy. A security.txt is published under /.well-known/.

  5. No cookies, no trackers

    The site sets no cookies and loads no analytics or embeds. The only stored value is the light/dark choice in localStorage, on your device.

  6. Caching without stale files

    Static assets and pinned libraries cache for a year. Site CSS and JavaScript URLs, including the import map that resolves every module, carry a version that changes on each deploy, so returning visitors never mix old and new files.

  7. Accessibility

    One h1 per page, semantic landmarks, a skip link, visible focus rings, 44px tap targets, keyboard-operable toggles, and AA contrast in both themes. The reveal animations have a failsafe so content can never stay hidden.

  8. Verify it yourself

    The home page has a "Don't trust me. Verify." panel. When you click it, your browser checks this domain live: HTTPS, HSTS and the Content-Security-Policy are read from a same-origin request, and SPF, DMARC, CAA and DNSSEC come from DNS-over-HTTPS (Cloudflare, then Google). It never runs on page load, nothing is stored or sent to this server, the TLS version is not claimed because JavaScript cannot read it, and if the resolvers are blocked it says so instead of reporting a failure.

Architecture

Sanitized diagram

Request flow: the browser gets static HTML from the host, then CSS and fonts; page scripts load after first paint; the particle scene loads last and falls back to a still image when WebGL or motion is unavailable.BrowserHTTPS onlyStatic hostno server codeSecurity headersCSP · HSTS · no cookiesHTML + CSSself-hosted fontsSite scripts~10 KB, after paintParticle scenelazy, versioned modulesFallback: still imagereduced motion · no WebGL2works with JS off
Request flow, simplified: static files and security headers first, page scripts after first paint, the particle scene last, with a still image as the fallback.

Results

What changed

  • Runs with JavaScript disabled and with reduced motion

  • No third-party requests, cookies or trackers

  • Lighthouse (local run): Accessibility, Best Practices and SEO 100; Performance 90+ on the home page

What I learned

Takeaway

The same rules that protect a clinical network apply to a personal site: default to same-origin, fail safe, version what you cache, and make every claim verifiable from the outside.

Tools used

Tools used

  • HTML5
  • CSS custom properties
  • JavaScript modules
  • three.js
  • GSAP ScrollTrigger
  • Apache/LiteSpeed .htaccess

Contact

Want the full story?

Happy to walk through the details, the trade-offs, and what I would do differently.