The Shilpa of Code — How I Built This Website

A story about crafting a personal website with Astro, Tailwind CSS v4, and a touch of Hindu mythology. From void to creation.

There is a hymn in the Rig Veda called the Nasadiya Sukta, the Hymn of Creation. It begins like this:

Then even nothingness was not, nor existence. There was no air then, nor the heavens beyond it.

Before anything, there was Shunya. The void. Zero.

Every personal website starts there too.


The Void — शून्य (Shunya)

For a long time, I had no personal website. I had code on GitHub, commits at work, PRs merged into codebases that aren’t mine to show. I had a LinkedIn that read like a résumé because it was a résumé. And I had a quiet certainty that someone who builds software professionally for a living should, at some point, build something for themselves.

That certainty sat in the void for years.

I’m a Staff Engineer at PhysicsWallah. I’ve built SDKs, architected Web Component systems, migrated monoliths, chased Core Web Vitals scores into the green. But the things that make me me, the obsession with mythology, the 20 years of gaming, the half-formed theory that the Bhagavad Gita is the best piece of product philosophy ever written, none of that had a home on the internet.

So I decided to build one. Not a portfolio in the corporate sense. Something more like a sansthan, an institution, a place of learning and identity. A space where the engineer and the devotee of karma could coexist.

I called it Beyond Code & Karma.


The Blueprint — वास्तु (Vastu)

Vastu Shastra is the ancient Indian science of architecture. Before a single brick is laid, the Vastu determines orientation, proportion, and energy flow. The building is designed in the mind before it exists in the world.

My Vastu for this site came down to three constraints:

It had to be fast. Not “acceptable on a good connection” fast. Instantaneously, offensively fast. I’ve spent too much time at work optimising LCP scores to let my own site be slow.

It had to cost almost nothing to run. I didn’t want to think about servers, databases, or uptime. Static HTML on a CDN is the correct answer to most content problems that aren’t actually dynamic.

It had to be mine. Not a Webflow template. Not a Next.js boilerplate with someone else’s design system. Every line of CSS should feel like I wrote it because I meant it.

Why Astro

Astro is the right tool for this kind of site. Not because it’s trendy, because it ships zero JavaScript to the browser by default, and every departure from that default is explicit and intentional. For a content site, that’s the correct stance.

Astro’s file-based routing means my mental model of the site matches its directory structure exactly. There’s no indirection, no framework magic routing table to decipher. src/pages/index.astro is /. src/pages/blogs/index.astro is /blogs. Done.

Content Collections sealed the deal. Instead of maintaining a headless CMS or hand-rolling a blog system, I define a Zod schema once, title, category, tags, publishedAt, and Astro gives me fully-typed frontmatter across every .mdx file. The TypeScript catches mistakes before they become 404s.

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    category: z.enum(['tech', 'mythology', 'gaming', 'life']),
    publishedAt: z.coerce.date(),
    tags: z.array(z.string()),
    draft: z.boolean().default(false),
  }),
});

Six lines that define the contract for every post I will ever write. That is good architecture.

Why Tailwind CSS v4

Tailwind v4 dropped the tailwind.config.js file in favour of a Vite plugin. Install @tailwindcss/vite, add it to your Vite plugins, and you’re done. No configuration file. No purge setup. No layer declarations.

// astro.config.mjs — that's the entire Tailwind setup
vite: {
  plugins: [tailwindcss()],
}

I use Tailwind for structural utilities but most of the design lives in custom CSS files scoped per page. The colour palette, --cosmos, --fire, --sacred, comes from a personal vocabulary, not a design system someone else wrote.

Why Bun

Because bun install is fast enough to feel instant, and the fewer tools in my mental stack the better. Bun as a package manager, Bun as a runtime for scripts, Bun as the command that runs everything. Simple.


The Craft — शिल्प (Shilpa)

Shilpa means craft. The Shilpa Shastras are Sanskrit treatises on visual art and architecture, written evidence that ancient India thought deeply about how things are made, not just what they mean.

Building this site was an act of shilpa. Here’s what the craft actually looked like.

The Design Language

I wanted the site to feel like Varanasi at 3am. Dark. Alive. Old and new at the same time. If you’ve ever stood on the ghats before dawn, the Ganga black and still, the distant chanting, the smell of marigolds and incense, you know the quality of that darkness. It isn’t empty. It’s full.

So the background is #07080d. Almost black. The primary accent is --fire: #ff8c00, the orange of a diya flame. Secondary warmth comes from --sacred: #c8953a, the gold of temple brass. Text is warm cream, never pure white, because nothing in that world is clinical.

The headings use Cinzel, a serif inspired by ancient Roman inscriptions, which itself carries an echo of Sanskrit stone carvings. Body text uses Crimson Pro, a literary serif that’s comfortable to read at length. Code uses DM Mono.

The Star Particles

80 of them. Each one is a div with randomised position, size, opacity, and animation duration. They twinkle. They’re completely useless to the site’s function and I could not imagine the homepage without them.

for (let i = 0; i < 80; i++) {
  const star = document.createElement("div");
  star.className = "star";
  star.style.cssText = `
    left: ${Math.random() * 100}%;
    top: ${Math.random() * 100}%;
    --dur: ${2 + Math.random() * 4}s;
    --max-op: ${0.3 + Math.random() * 0.5};
  `;
  starsContainer.appendChild(star);
}

I spent longer getting the timing functions right than I spent on the entire deployment pipeline.

What Was Hard

Tailwind v4’s alpha-state documentation. The v4 API changed significantly from v3. Several things I expected to work the way I remembered didn’t. I read the source code more than I read the docs.

Getting the custom cursor to behave on mobile. A cursor: none rule on body hides the native cursor on desktop, which is what you want, so the custom cursor takes over. But on touch devices, there is no cursor to hide, and cursor: none just makes the experience slightly worse. The fix: scope it to @media (pointer: fine).

@media (pointer: fine) {
  body { cursor: none; }
}

One media query. Obvious in hindsight.

The gaming stats tracker. The /svssdeva/tracker page fetches live data from the Fortnite API and Marvel Rivals API at build time and bakes the stats into the HTML. If either API is down when I deploy, the build still completes. It falls back to a snapshot. Building resilient static data fetching is more nuanced than it sounds.

What Surprised Me

Astro’s build speed. The entire site, seven pages, two external API calls, full CSS processing, builds in under 15 seconds. Every time. That’s fast enough that I never think about whether to run the build.

The zero-JS constraint feeling liberating rather than limiting. When you can’t reach for useState as a reflex, you think harder about whether interactivity is actually necessary. Most of the time it isn’t. The game filter tabs on the svssdeva page are 20 lines of vanilla JS. They work perfectly.


The Offering — अर्पणम् (Arpanam)

Arpanam is the act of offering, placing something before the divine without attachment to the result.

Deploying a personal site is a small arpanam. You put it out into the world not knowing who will read it, whether it will matter, whether the work was worth the time. You do it anyway.

The deployment is a single script:

bun build && ./deploy-mac-linux.sh

The script syncs the dist/ folder to an S3 bucket in eu-north-1, then invalidates the CloudFront distribution. The site is on a CDN. It loads fast everywhere. It costs a few dollars a month.

aws s3 sync dist/ s3://xxxxxxxxxxxx-xxx --delete
aws cloudfront create-invalidation \
  --distribution-id $CLOUDFRONT_DISTRIBUTION_ID \
  --paths "/*"

No CI/CD pipeline. No deployment dashboard. No Kubernetes. A bash script and an AWS CLI.


The Karma Loop — कर्म (Karma)

The Bhagavad Gita says: कर्म करो, फल की चिंता मत करो. Do your duty without worrying about the fruit of your actions.

I’ve been thinking about this a lot as it relates to building in public.

The natural impulse when you create something is to immediately check whether it’s being received. Analytics. Stars. Views. Validation. The fruit. But the Gita is asking you to focus on the action itself, to do good work as an end in itself, not as a means to approval.

This blog is an exercise in that. I’ll write about code, about mythology, about gaming, about the strange territory where all three overlap. Some of it will land. Some of it won’t. I’ll write it anyway.

The name Beyond Code & Karma is the thesis: there is something past the code, past the metrics, past the job title. A practice. A craft. A way of showing up, in engineering, in life, that isn’t transactional.

I don’t know if this website will become something or quietly exist in a corner of the internet forever. Genuinely both outcomes are fine, though I notice I check the analytics more than I probably should.

The work is the point.


If you want to build something like this yourself, the stack is astro 6, Tailwind CSS v4, deployed on S3 + CloudFront. Ask me anything.

☀ Try The Archive