This is the first post on the new notes section. I'm using this space to share thoughts, technical write-ups, and anything else I find interesting enough to put into words.
I rebuilt my personal site as a technical exploration: what can vanilla HTML, CSS, and JavaScript do in 2026 without heavy frameworks or complex tooling? The answer: more than you'd think.
This is a breakdown of the architecture, the implementation choices, and the techniques that made it work.
Why Write
Writing forces clarity. When I try to explain something in prose, I discover the gaps in my own understanding faster than any other method. Rubber duck debugging, but for ideas.
What to Expect
You'll find a mix of:
- Technical notes and command references
- Opinions on software and tools I use day to day
- Longer-form writing on topics I care about
No fixed format — whatever the content calls for.
The best tools are the ones you forget you're using.
Design Goals
- Narrative introduction for first-time visitors
- Instant access for returning visitors
- Cinematic visuals without framework overhead
- CDN-optimized performance
- Buildable in a single day
- Minimal build tooling
The site uses a lightweight Node.js build script to process Markdown posts into static HTML. The build step handles templating and content generation, but the output is pure static files — no server-side rendering, no client-side framework, no runtime dependencies.
Architecture Overview
The site is built with a simple Node.js script that processes Markdown posts into static HTML. The build pipeline:
- Reads
.mdfiles from central directory with frontmatter (title, date, domain_tags, abstract) - Parses Markdown to HTML using
marked - Injects content into HTML templates
- Generates a blog index sorted by date
- Copies static assets to
build/
Dependencies are minimal: gray-matter for frontmatter parsing, marked for Markdown rendering. The output is static HTML, CSS, and JavaScript — no runtime framework, no server-side logic.
// Simplified build flow
const { data: fm, content } = matter(markdownFile);
const contentHtml = marked.parse(content);
const output = template
.replace('{{TITLE}}', fm.title)
.replace('{{CONTENT}}', contentHtml);
fs.writeFileSync(outputPath, output);
This approach keeps the development experience fast while maintaining the deployment simplicity of static files.
View Transitions API
The intro-to-portal transition uses the View Transitions API. It's a single line of JavaScript that morphs between pages like a native app:
document.startViewTransition(() => {
window.location.href = 'index.html';
});
Browsers that don't support it fall back to instant navigation. Progressive enhancement at its simplest.
Typewriter Engine
The intro sequence uses requestAnimationFrame for smooth text accumulation. No libraries. The engine tracks character position, handles line breaks, and triggers the next phase when complete:
function typeText(element, text, callback) {
let index = 0;
function type() {
if (index < text.length) {
element.textContent += text[index++];
requestAnimationFrame(type);
} else if (callback) {
callback();
}
}
type();
}
Sixty frames per second, hardware-accelerated, zero dependencies.
Visitor Flow Logic
First-time visitors see the story. Returning visitors (within 12 hours) skip straight to the portal. The logic lives in a <script> tag in the <head>:
const lastVisit = localStorage.getItem('return_visit');
const twelveHours = 12 * 60 * 60 * 1000;
if (!lastVisit || (Date.now() - parseInt(lastVisit) > twelveHours)) {
window.location.href = 'intro.html';
}
A query parameter (?skipped=1) overrides the redirect for testing. The intro page sets the timestamp when it completes.
CSS Architecture
Modern CSS does the heavy lifting. Custom properties for theming, backdrop-filter for glassmorphism, mix-blend-mode for text effects, and keyframe animations for the background motion:
.hero-core {
backdrop-filter: blur(20px) saturate(180%);
background: rgba(17, 25, 40, 0.75);
border: 1px solid rgba(255, 255, 255, 0.125);
}
@keyframes drift {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20px, -20px) scale(1.1); }
}
No preprocessor. No utility classes. Just semantic HTML and scoped styles.
What Worked
Speed. The entire site loads in under 200ms on a cold cache. Static files on a CDN are still the fastest architecture.
Flexibility. I changed the intro sequence three times during development. No build step meant no friction. Edit, refresh, ship. Always through LLM of the week (Claude + Gemini depending on my token availability).
Clarity. The codebase is small enough to hold in working memory. When I come back in six months, I'll understand it in five minutes.
What I'd Change
Content strategy. The "Recent Notes" section on the homepage is still hardcoded HTML. The blog index is generated automatically, but the homepage preview cards aren't. Next iteration: extend the build script to generate those cards from the same post metadata.
Mobile refinement. It works on mobile. It doesn't sing on mobile. The event horizon visual needs better responsive scaling. The stats banner feels cramped below 375px. I'll iterate. (I'd like to point out that Claude wrote both this callout, and the "cramped" stats banner its concerned about...)
The LLM Factor
This was the first project where I used AI tooling throughout development. Not to generate the site, but to accelerate iteration. I'd describe a visual effect and get implementation options. I'd paste CSS and ask about performance implications. I'd sketch logic in plain English and refine the code it returned.
The result: faster exploration, less context-switching, more time in flow state. The code is still mine — every line was written or rewritten by hand — but the feedback loop was tighter. Less friction between idea and implementation.
This is what I'm calling VibeCoding: building with AI as a thinking partner, not a code generator. The tool doesn't make decisions, but it removes the small blockers that used to break concentration. I'm watching this space closely.
Closing Thoughts
Modern web capabilities — View Transitions, requestAnimationFrame, CSS custom properties, backdrop-filter — make it possible to build fast, beautiful sites without heavy frameworks. The constraint of vanilla JavaScript forces clarity. A minimal build step keeps the development experience fast.
Posts here are written in Markdown and built into static HTML — no database, no CMS, no server-side rendering. Just files and a small build script. Fast, version-controlled, portable.
This site loads in under 200ms, works offline after first visit, and will run unchanged for years. That's the power of keeping it simple.
The code is available on GitHub. The techniques are portable. The approach scales down better than it scales up — but for personal sites, portfolios, and landing pages, it's more than enough.