Skip to content
Balwan Bamniya, home
Menu
Back to work

Case study

This portfolio

A fast, content-driven freelance site built to turn the right visitors into email conversations — static Astro on Cloudflare Pages, with zero JavaScript on every page but one and a typed content pipeline for case studies.

#Astro 7#TypeScript#Tailwind CSS 4#MDX#Svelte 5#Cloudflare Pages
The balwanbamniya.xyz home page with the headline "Fast, reliable software for ideas worth building." and a current-focus panel.

The problem

I work with startups and growing teams outside India, and most of them first meet me through a link. In those first few seconds the site has to answer three questions: Can this person build what we need? Can we trust them? How do we start?

Most developer portfolios answer the wrong ones. They show technology logos, animated hero sections and placeholder projects. I wanted the opposite: a site that reads like a consultant’s proposal, loads instantly on a mid-range phone abroad, and has exactly one call to action — an email.

It also had to be honest. Until real case studies existed, the work page needed to say so rather than fill the space with invented outcomes.

What I built

Everything from positioning and copy to the design system, information architecture, content model, build pipeline and deployment:

  • Five content pages — home, services, work, about, contact — plus notes and generated case-study routes.
  • A typed content pipeline for case studies and notes, with a draft gate and reusable MDX components (the diagrams, callouts and figures on this page).
  • A warm editorial design system: ivory, paper and ink tokens, a serif/sans pairing, visible focus states and reduced-motion support.
  • Build-time assets: the Open Graph image, sitemap and robots.txt are generated during the build from one config file.

From content to edge

  1. Source

    • siteConfigName, domain, email, links
    • Content CollectionsZod-validated MD/MDX
    • Astro componentsStatic by default

    astro build

  2. Build output

    • Static HTMLOne file per route
    • Optimised imagesSharp, responsive srcset
    • og-default.pngRendered from SVG
    • Sitemap + robotsCanonical domain only

    git push → Cloudflare Pages

  3. Edge

    • balwanbamniya.xyzGlobal CDN, no server runtime

Key decisions

Hard problems

1. Drafts that never leak

Case studies are written over days, sometimes with placeholder screenshots. They must be previewable locally but never appear in production routes, indexes or the sitemap. Every collection query goes through one predicate:

export const isVisibleEntry = ({
  id,
  data,
}: {
  id: string;
  data: { draft: boolean };
}) => !id.endsWith("template") && (!data.draft || import.meta.env.DEV);

src/lib/content.ts

Because routes are only generated for visible entries, the sitemap integration can’t list a draft that has no page.

2. A share image that can’t go stale

Link previews are often the first impression. Rather than a hand-made PNG that drifts from the site, /og-default.png is an Astro endpoint that builds an SVG from siteConfig and rasterises it with Sharp during the build:

export const GET: APIRoute = async () => {
  const name = escapeXml(siteConfig.name);
  const role = escapeXml(siteConfig.role.toUpperCase());
  const svg = `<svg width="1200" height="630">…${name}…${role}…</svg>`;
  const image = await sharp(Buffer.from(svg)).png({ quality: 90 }).toBuffer();
  return new Response(new Uint8Array(image), {
    headers: { "Content-Type": "image/png" },
  });
};

src/pages/og-default.png.ts (SVG markup trimmed)

3. Case studies that carry evidence, not adjectives

A recruiter scanning a case study needs the problem, my role, the architecture, the hard parts and the outcome — fast. Plain Markdown pushes everything into prose. I extended the content schema with role, timeline, status and an “at a glance” metrics strip, and built a small set of static MDX components — architecture tiers, flow steps, decision callouts, metric grids and screenshot figures with placeholder states. Each is plain HTML and CSS, readable by screen readers and stacking cleanly at 390px.

The contact page at 390px wide, with Write an email and Copy email buttons below the headline.
Contact at 390px. The email link works without JavaScript; the copy button is the site's only hydrated component.

Outcome

JavaScript on home, services, work, about, notes and 404
0 KB
Gzip JS on contact, including the Svelte runtime
~13 KB
Gzip HTML per page
2.5–5.5 KB
Gzip CSS, one shared file
~12 KB
Measured from the production build output (dist/) in October 2026.
  • One build command produces the full site, sitemap, robots file and share image, deployed as static files on Cloudflare Pages.
  • The work archive launched with an honest “in preparation” state and switches automatically to case studies when they’re published.

What I’d change