Personal sites are in a new era: IDE, agents, and git cover a lot of ground that used to mean "open WordPress" or "log into the CMS." You still own the words — you're often not starting in a hosted dashboard.

bagusfikri.me was never a resume. It's one place for long articles, half-formed ideas, and crafts (OSS, demos, anything easier to show than to thread). I've built hero-and-cards sites for clients; here prose, links, and embedded work do the work.

This piece is that decision in practice — constraints, stack, how content is stored — and the human-readable companion to project.md in the repo.

The brief

Here's what I told myself the site had to feel like:

dark first, terminal, Palantir-flavored — matte field for type; monospace rhythm, grid logic, sharp corners; session, not bounce. "Palantir" here means discipline — color as signal, quiet chrome, precision over novelty — not enterprise clutter. The reading column should feel like a tool, not a gradient brochure.

Those three threads have to agree. The through-line is low chrome, high clarity.

Reading first

Single column, max-w-2xl, px-4 — long reads without viewport stuffing; enough structure for short notes too. Geist Mono, small body, relaxed leading — a log, not a terminal dump.

Color tokens live in src/app/globals.css. Copy survives daylight; tags stay on AI, DESIGN, META, THINKING, READS. Radius: zero; links hover subtly. No auto-scroll, auto-focus, or redirects.

ASCII animation

A living signal, not a hero still — the header animation runs on a custom AsciiHeader component cycling through generated patterns. Abstract, but biased toward how I think — not stock hacker wallpaper. Most raw thinking lives in Obsidian; Cursor and agents interpret it under project.md rules.

live

The animation sits in the corner, ambient and peripheral. Hard to read at a glance is intentional — it's tone control, not content.

The stack (small on purpose)

Next.js App Router, React, TypeScript, Tailwind v4, tokens in global CSS. Boring on purpose: open Cursor, edit, ship.

Cursor, end to end

Cursor handles drafting, implementation, and review in one place. AGENTS.md and project.md steer agents off generic "startup landing" output.

New behavior usually starts as a plain-language prompt — intent, limits, what to skip. The agent proposes types and file touches; I review. Two sessions below: a bilingual reader UI we tried (manual EN + ID bodies, no machine translation), now shelved until there's a translation API worth wiring in. Then scroll to top + copy URL.

Cursor session: prototype bilingual tabs (not shipped)
Cursor session: prototype bilingual tabs (not shipped)

Cursor session: prototype bilingual tabs (not shipped)

Cursor session: scroll to top and copy link
Cursor session: scroll to top and copy link

Cursor session: scroll to top and copy link

The same loop updates rules and philosophy, not only UI. project.md is the long-form contract for voice, layout, tokens, and what to refuse; AGENTS.md points agents at it and the Next.js guardrails. I extend both with the same plain-language asks I use for features — so agents don't just ship code; they inherit how to write and design this site. Below: adding thread-paced article prose.

Cursor session: adding thread-pacing writing rule to project.md
Cursor session: adding thread-pacing writing rule to project.md

Cursor session: adding thread-pacing writing rule to project.md

Agent as CMS

No hosted CMS as source of truth — git wins: src/content/posts/ for shipped Post modules, content/articles/ for drafts, public/ for media. Vercel deploys; agents patch like I would — agent as CMS. You still need constraints and judgment; LLM-assisted + static often beats a second database here.

Some error is expected. Article bodies live in .ts as template literals; markdown-style backticks inside the string can kill the build fast. I screenshot the overlay, ask the agent to fix it, and keep going — same loop as features.

Next.js build error: parsing article module
Next.js build error: parsing article module

Next.js build error: parsing article module

Raw captures live in photo-video/; copies for this piece sit in public/media/building-this-site/.

In the IDE and the playground

This is where everything lives: one editor, one repo, one deploy. The animation playground is a scratchpad route — a place to try motion ideas before they touch the main site.

Screen recording: animation playground

Where content lives — for now

content/articles has numbered stages 00–04, templates, CATEGORIES.md, README — planning and taxonomy in git, no dashboard.

content/articles pipeline: brainstorm through published, templates, and category notes
content/articles pipeline: brainstorm through published, templates, and category notes

content/articles pipeline: brainstorm through published, templates, and category notes

Live posts: one .ts module each in src/content/posts/ — typed Post, routed via writing/[slug], collected in index.ts. Markdown plans; .ts ships — typed, reviewed, diffable.

Crafts can be routes in the same app. Work starts in content/articles; when it's ready, it graduates to src/content/posts/.

Making this more useful later

Still reading-first, but useful — not just PDFs of thought.

  • Code / live demos beside prose.
  • @bagus_bot on X for depth without noisy widgets.
  • Comments — slow, optional, per post.
  • Light analytics — signal, not obsession.

No fixed timeline — shape only.

Articles, ideas, crafts — public without performance. You're reading one moment in that log.

This is the beginning. I'll keep developing how to produce content and improve the site — including improving my writing. It's so bad, I know.