Every entry is a cbv: commit → Codeberg push → vercel --prod on
anirudhux.vercel.app. Newest first. Each entry is a checkpoint — the
commit is the rollback target in git, the deploy in Vercel's history.
The contract (from 2026-07-17): the entry is written during the cbv
itself — gates pass → deploy → entry gets the deploy URL → commit rides with
it. Nothing ships without a line here. The seed below (2026-07-09 → 17) was
distilled from the commit history; pre-17 deploy URLs aren't recorded
(Vercel's dashboard maps them by commit metadata).
Removed the Google Analytics gtag block from app/layout.tsx (the only GA
reference in the repo) and replaced it with the PostHog snippet, US cloud.
The snippet rides as a script constant in <head>, after the theme and
loader scripts so it stays off the first-paint path; it loads array.js async.
The project API key is public-safe and committed in the clear on purpose, the
same call as the Web3Forms key: it is a client-side ingestion key, and a
static export inlines client config into the bundle regardless.
Verified on dev: PostHog initialises against us.i.posthog.com, the key is
live (remote config loads, no 401), and events reach the ingestion endpoint;
GA is fully absent (no gtag, no dataLayer, no googletagmanager).
2026-07-23 · Highlights breathes at 821–900; UPI thumbnails; a sitemap
Highlights responsiveness (821–900px): the two-column shell (bio beside
feed) turned on at 821, but the feed is a single fused column that takes its
full-width form at ≤900, so in that gap the feed was crammed into 66% and the
bio starved to a word per line. It now stacks (bio header over the full-width
feed) through the whole window and splits into two columns at 901, where the
wide mosaic has room. Scoped to html:has(.hl2-zone), so AI, Work, and
Community keep their 821 desktop layout.
UPI Lite and UPI International thumbnails: two causes. On the phone rows
the cards had no TILE_PREVIEW, so they rendered copy-only; added both,
pointing at the real case-study stills. On tablet and desktop object-fit: cover cropped the wide 3:1 UPI Lite montage to a blank centre slice; a
scoped object-fit: contain (the PhonePe device montages only) shows the
whole image. The photo heroes keep cover.
SEO surfaces: added app/sitemap.ts, emitting out/sitemap.xml at build.
It is driven by isCaseLive, the same gate the route prune uses, so the
sitemap and the real routes cannot drift; 17 live URLs, zero pruned
placeholders. robots.txt gained a Sitemap: line, and llms.txt now points
agents at both.
2026-07-23 · The prune: dead routes out, case pages close clean
Route prune (Anirudh's call, from the site-tree parley): the eight
"page to be rebuilt" placeholder routes are deleted: en-platform,
en-design-system, en-printer-toolkit, nutella-400g, uci-certification,
adori-interactive, phonepe-b2b, vyu-hul-3-roses. generateStaticParams
filters by isCaseLive; a missing study is a 404 in dev too. NDA and
locked bento rows stay; the prune touches routes only. The withheld
Vyu × HUL project no longer has a URL naming the client relationship.
The Contact band is off all 11 case studies (option B of the audit):
it duplicated the sectional footer's Connect column and its collapsed
teaser read as a half-painted form. Case pages close on the footer; the
form lives in the two dialogs.
Case vnav travel ends at the prose. The toc was a bare grid child,
so its sticky track ran the whole .case-body and it kept riding beside
gallery/embed/Read more. It now sits in a .case-toc-col stretched to
row 1 only.
Design System tile: lock + NDA aligned on the row mechanism. The
pair was dropped inline into the h2 with no flex context and sat at two
heights. .tile-nda-pair gives it the rows' flex centring, seat
measured against the row chip; structural for any future NDA_TILES
member.
2026-07-23 · The register purge: the site stops sounding machine-written
Site-wide text audit (Anirudh's call: "em dashes, LLM-isms, X-not-Y...
all the stuff has crept back in"): roughly 150 fixes across all ten
case studies, every blurb/positioning/proof line in content.ts, the UPI
figure captions, card ledes, hire timeline plus its pill-tooltip twin,
best-fit cards, NDA tooltips, and llms.txt. His register throughout:
semicolons, colons, full stops; en-dash year ranges. The stale
"Narrated: play with sound" caption died with the mute.
The law is now structural: CLAUDE.md carries the register law, and
smoke fails any build with an em-dash or ", not " pivot in rendered
copy. Exemptions are allowlisted by his ruling: Hareesh's verbatim
testimonial, the authored hero closer, and this ledger's history.
The root cause is on the record (memory: voice-register): the rule was
written all along; the failure was generation without application. The
gate exists because intention decayed twice.
2026-07-23 · ONE footer sitewide; Constella's dark head trimmed
Constella's light walkthroughs trimmed (his catch, mis-filed as a
switching bug — it was the FILE): both light captures opened on ~2.7s of
the app's dark loading screen, visible at every loop restart and instant
theme swap. Heads cut past the fade (3.05s / 2.95s desktop / mobile),
re-encoded near-lossless; frame-one luminance measured light on both.
2026-07-23 · Instant theme-swap footage; every video force-muted
Theme pairs stay mounted (Anirudh's catch: Constella stuttered for
seconds on a mode flip, then popped). The old key={src} remount
refetched + redecoded the other capture on every flip; now both captures
mount and CSS picks by data-theme — the case-fig still technique promoted
to videos (CardVideo + CaseFigureVideo). A playback-sync effect pauses
the hidden one (display:none doesn't stop playback), and the pair rules
wear doubled classes (.case-figure video at (0,1,1) would out-rank a
lone class). Measured: the incoming capture is on screen at readyState 4
in the same tick as the switch click.
Site-wide mute (owner's call): all three renderers set muted plus a
volumechange guard that snaps any unmute straight back; WebKit's volume
controls are CSS-hidden. UPI Lite's narration track stays IN the file —
player policy, reversible — but no player ever sounds.
2026-07-23 · anirudhux.com — the site moves to its own name
The custom domain is live: apex + www attached to the project (Namecheap
A @ → 76.76.21.21, www CNAME → cname.vercel-dns.com — Anirudh's DNS,
minus a leftover Namecheap URL-redirect record that was round-robining
the apex to their parking IP). siteUrl → https://anirudhux.com, so
canonicals and OG URLs carry the real name; anirudhux.vercel.app stays
as a working alias.
Google Analytics (gtag.js, G-KJYG4332SF) added in the root layout head —
one tag, every page, verified in every exported HTML file. The paint-
gating theme/loader scripts stay ahead of it.
2026-07-23 · The résumé ships everywhere; the blurb finds its arc; Design Lead, since 2014
Deploy: anirudhux-biwl3bpcd-anirudhux.vercel.app
The résumé is live — typeset from the owner's cut, exported to PDF,
hosted on Drive (deliberately off-Vercel), and surfaced at every contact
point: the footer's Connect column, a "View résumé" pill leading every
contact drawer (résumé → X → LinkedIn), a secondary CTA beside "Get in
touch" in the Hire me hero, and a line in llms.txt for the machines.
One constant (socials.resume) feeds them all. robots.txt added.
The intro blurb, final cut (owner's words): "Observing, connecting &
designing since 2014. Shaped 400M+ touchpoint experiences across digital
domains; now building for humans & agents." Four lines on phone and
desktop, three on tablet — wrap discipline held per band.
The bracket + year sweep: title tag / OG / description / share card
re-filed from "Product Designer" to Design Lead (the resume's lesson
applied to the site), every "2015" → 2014, the hire stat → 12+ years.
og.png re-baked from its generator with the site's middot, no em-dash.
Resume working drafts moved OUT of public/ into gitignored
resume-drafts/ (repo is public; public/ ships — neither may ever carry
them). The draft commit was dropped before it reached the remote.
Verified on prod: /resume/draft-v1.md → 404. Also re-bakes the ledger,
so the previous entry now renders on /changelog.
2026-07-23 · Community re-composed: the marquee column
Deploy: anirudhux-oy92kddsw-anirudhux.vercel.app
The big column carries the two marquee credentials — Transform Design
(founded) over GitLab Talk — and the small column stacks Various Meetups /
PR;SOS / DARD at 40:30:30 (lands 39:31:31 on content minimums). Founder
beats attendee, talk beats circuit. Phone card flattens in the same
order.
2026-07-23 · The clamp LAW + an honest bench; Transform Design goes big
Deploy: anirudhux-8b72yrryj-anirudhux.vercel.app
The rule, made structural (after the Contraire truncation call-out):
every Highlights card lede fits its clamp — 3 lines max, an ellipsis is a
defect. Root cause was systemic: CARD_COPY held ledes "sized for the big
slot" while the bench reorders slots freely, plus a duplicate contraire
key silently shadowing fixes. All ledes now fit the SMALLEST slot
(owner copy only: Contraire's tagline line, Constella's opening clause,
UPI Lite's blurb, Shape's closing line — the two original mobile-lab
clamp debts paid). Smoke now asserts clamp integrity on every route ×
viewport × theme: a truncated lede fails the build gate. It caught three
offenders across bands on its first runs.
The bench shows slots — each row's number carries its feed slot
(1 HERO · 2 BIG · 3-4 SMALL · 5-6 BIG · 7-8 SMALL…), computed from feed
position (hero-first) so it never lies. Slot size was position-derived
CSS the bench kept hidden — reorders were blind; now they're sighted.
Feed re-curated via the bench (owner): Transform Design → slot 5
(BIG), Shape → 7 (small); Shape's lede refitted to the small card.
Card title "TransformDesign.co" → "Transform Design" (the unbreakable
18-char word clipped h1s); lede = the tagline; case-prose links now
styled sitewide; gallery crops bias the upper third.
2026-07-23 · TransformDesign.co — the founding credential joins Community
Deploy: anirudhux-i2ly8qi6y-anirudhux.vercel.app
/community/transformdesign — the meetups recipe: positioning + "The
movement" (the org's own tagline; the 2019–2020/COVID ending lives in the
body — leading with it read as a eulogy) + "The people" (Shami Raj,
co-founder and mentor; 12 speakers linked BY NAME ONLY — no titles, no
employers anywhere, "seasoned designers and design leaders in the
industry" as the blanket) + a 13-photo wall (people & ambiance, latest
conference first, TDConf3-Mix packed-room hero) + all 11 promo artifacts
in one period-piece bundle (TDConf4's in-artwork employer names stay).
Community tab: TransformDesign LEADS Practice (founder beats
attendee); family copper fixed (missing tiles.ts entry had it falling to
the forest-green default). Curated into Highlights via the bench — its
feed card carries the hero still (the walkthrough-404 trap, caught by
smoke).
Class-level fixes found on the way: .case-prose a did not exist —
every case-page link rendered as plain ink; now family-coloured +
underlined, sitewide. Gallery cover crops bias to the upper third
(centered crops decapitated standing subjects).
2026-07-22 · Highlights stills + /changelog goes public (unlisted)
Deploy: anirudhux-ji1venzgj-anirudhux.vercel.app · re-baked as
anirudhux-1zwwo1jpw so this very entry renders on /changelog (the page
bakes at build time, so the ledger runs one deploy ahead of it)
Every Highlights card has a face again. Cards without a walkthrough
recording fell through to /projects//walkthrough.mp4 — a SILENT 404
(browsers don't error a missing ), so the post-recording-era
highlights (UPI Lite · UPI International · Various Meetups, curated in via
the bench today) ran bare petrol scrim. New CARD_STILL map: a declared
still wins the media seat in the same fill recipe — ftux / forex-anxiety /
hero per the first-big-image rule; one-line swap per card; delete the
entry when real footage lands. Verified on prod: 4 videos + 3 stills,
zero blanks.
/changelog — this ledger as an unlisted page: CHANGELOG.md rendered
at build time, URL-only access (no surface links to it), site rails.
Proof-of-build, in the owner's own checkpoints.
2026-07-22 · Work tab: NDA chips across the gated stack; notes align
Deploy: anirudhux-afz0skbch-anirudhux.vercel.app
Lock + NDA on the whole gated stack: Ennteract 2.0 · Printer Toolkit ·
Vyu · Design System (tile AND phone card) · PhonePe consumer study join
B2B Gateway + ExpressBuy — play stubs gone (no implied walkthroughs).
The nda contract re-written to Anirudh's definition: the reader can't
access this BECAUSE of an NDA; it says nothing about the future. Tiles
gained the state via NDA_TILES (chip in the title line, corner icon off
while inert).
Row note alignment: every note sat 6px left of its title — the 9.5px
indent forgot the head's flex gap (tick 3.5 + margin 6 + gap 6 = 15.5).
Fixed class-level; title and note left edges now identical.
Design System hover reveal parked: the Shape tablet placeholder leaked
another project's face onto the tile; no preview until the real hero
exists (re-add instructions in tile-previews.ts).
2026-07-22 · Hire me becomes a TRUE dialog — the page-hybrid is dead
Deploy: anirudhux-94h5yh8ne-anirudhux.vercel.app
The philosophy, made structural (Anirudh): clicking Hire me must never
take a visitor off the core messaging — once people leave into a page,
they don't come back. Hire me (which is ALSO the About surface) is now one
native dialog, callable from every door: nav pill, footer link, identity
line. Content extracted to HireMeContent, dialog global in layout,
lazy-loaded on first open. DELETED: the iframe modal, its Escape relay,
HireDialogClose, the standalone page composition.
The address contract: in-site open writes /hire-me, close restores the
origin path; a shared /hire-me link renders the homepage with the dialog
auto-open (mount race solved with a pending-open queue), close lands on /.
/hire-me joined HOME_PATHS (the load-bearing template exemption).
Inside the dialog: CaseToc survived with a scrollRootSelector (the
panel is the scroller — it's the LAYOUT as much as the nav; removing it
let prose sprawl past its 720px measure). Colophon became "Tools I work
with" (the FULL roster; the built-with subset lives on in the footer
tooltip). Contact joined the index AND the column — the full-width band
treatment stays case-pages-only, where a real footer follows it. Page-era
forehead/chin trimmed (~123px head, ~127px tail → ~33px each).
Found in passing: the old "round N → date" comment scrub had corrupted
20 background 0.*s transitions (backg2026-07-22.2s) — silently
invalid since that pass, hovers snapping sitewide. All repaired.
2026-07-22 · Footer v2: brand stack, family wash, and the Tools dialog
Deploy: anirudhux-3c9hi7njh-anirudhux.vercel.app
The tool roster gets ONE source — lib/tools.ts (19 tools, builtWith
booleans). Three surfaces render from it and can't drift: the /hire-me
Colophon (BUILT_WITH — what this site was built with: Claude Code ·
Codeberg · Figma · Vercel · Phosphor Icons · Coffee), the footer's new
Tools dialog (the FULL working roster, three-column chip grid, Contact
dialog's exact header technique — no eyebrow variants), and the slim
footer's Built-with tooltip. Rotato + Supabase joined; Clideo cut (no
mark). All marks normalised to 18px across svg/raster/emoji, class-level.
The wash wears the ACTIVE TAB's family colour, fixed — petrol / moss /
forest / copper via --footer-accent from TAB_COLORS. The cycling
hero-accent read out of sync with the page ("this altering thing is not
working"). Family colours are identity, not ambience.
2026-07-22 · Category tabs adopt the Highlights close — one ground to the footer
Deploy: anirudhux-1qv535tw6-anirudhux.vercel.app
The footer gap collapses: the category tabs' clamp(80px,12vh,134px)
white band above the footer becomes 28px — the same rhythm as the
Highlights slab's own pad. Last tile → footer is now 36px.
The dot ground is unwalled (Anirudh's recon call): the T1's dot field
was an inset:0 layer clipped by .intro-tile's overflow:hidden — sectioned
in, so it stopped 36px short of the footer while the Highlights column ran
straight down. Desktop-only: the tile goes overflow:visible and the field
extends past the tile by the exact seam (8px stage edge + 28px footer pad),
so the bottom-weighted mask paints dots down to the footer hairline. Gap
measured 0 on prod. Highlights' T1 excluded (its sticky column already owns
its ground); tablet/phone bands untouched.
2026-07-22 · The Highlights feed staggers like the tiles
Deploy: anirudhux-blzase0dg-anirudhux.vercel.app
Per-card enter for the feed — the enter/exit classes moved off the
feed's wrapper (which faded the slab as ONE block, the last lens-era tell)
and onto each card: tile-enter at the tiles' own 70ms-per-index cadence
(verified 0/70/140/210/280ms on prod), uniform quick sink on exit. Same
keyframes and curve as the category tiles — all four tabs now enter with
one voice. ≤820 the page-plane owns all motion, so both band blocks null
the card stagger exactly as they null tile stagger.
Standing decisions logged with it: the Highlights T1 stays the
introduction surface and the identity line stays on the category tabs —
both retire only when the T1 talking-head videos land (the "social
anchoring" seat), nothing before.
2026-07-22 · Succession: Highlights2 IS the homepage — the lens is dead
Deploy: anirudhux-1noh9qmi0-anirudhux.vercel.app
The Highlights ⇄ All lens split is gone. The Highlights lens rebuilt as
a tab (born "Highlights2" on animation-lab, renamed to Highlights the same
day) is the front door at / and the first of four peer pills. Every view
move is now ONE machinery — exit → meta-card VT morph → staggered enter —
with a fade-through variant when Highlights is either side of the switch
(the stock cross-fade double-exposed its display T1 onto the category
statements). Deleted outright: the Lens state, flip/flipToAll
choreography, the dual-layer CSS (lens-exit/enter-*, .lens-flip-in),
ShowcaseFold's fold component, and TestimonialsFeed (fold-only). The feed
pipeline (buildFeedRows → FeedCards) and CompanyPills survive as the single
shared copy in ShowcaseFold.tsx.
Bands: phone keeps its own language (centered header — wave · 28px name
· segment-wrapped bio · pills — over the fixed dot ground, fused feed card);
tablet keeps its form (34px name, authored t1-break two-liner, full-width
fused slab). One real bug fixed on the way: the hl2 grid items auto-placed
into a fractional track on the 2-col phone grid (the .case-body
implicit-column RCA) — they now span 1 / -1.
Also riding (animation-lab merge): the sectional footer (portrait +
Highlights/Explore/Connect columns, joins the scroll on every tab), hl2
page-flow scroll (sticky static column, glass under the nav), the T1
top-anchor (copy hangs 13% below the tile's top on all tabs), Contact
seated bottom-left of the Highlights column until the talking-head video
chip claims that slot, tooltip surface 97%.
Addresses hold://ai/work/community all server-render their
view; legacy #all-* still self-heals; loader stays a front-door-only
ritual. Smoke: 15 routes crawled, no dead links / overflow / console
errors.
2026-07-22 · Every case study loses its orphan lede; highlighter + real sub-headings
Deploy: anirudhux-4te9ybg9c-anirudhux.vercel.app
The unnamed opening paragraph is gone from all nine case studies. Three
surfaces were answering "what is this" before the reader learned anything:
the positioning line (from content.ts, also powering the bento tile), a
free-floating lede in the md, and — on UPI International — a section literally
called Overview. The lede sat outside the TOC (which indexes ## only),
so it belonged to nothing. Now: title → positioning → a NAMED first section.
"Overview" is gone from the codebase; DARD and PR;SOS had substantive ledes,
so they were promoted to sections titled with Anirudh's own opening sentences
("The gap I went after", "I picked the mess on purpose") rather than deleted.
Four were pure restatement and were cut only after checking each against its
positioning line.
Editorial pass: 32 highlighted phrases + ~25 bolds across all nine, on the
load-bearing lines ("design success is not product success", "it scaled with
the vulnerability of the person in front of it"). Reuses .marker, the
half-height highlighter from /hire-me, so it inherits each page's family
colour. box-decoration-break: clone so a phrase that wraps paints on both
lines — half a marker stroke reads as a rendering fault.
.case-prose h3 did not exist. Tailwind's preflight strips heading
defaults, so every ### rendered at body size and weight with no air, reading
as a stray sentence. Now 17px/700/family colour with 34px above — one step
down from h2 (22/750). Dark added to the same rule, not left as a
light-mode-only fix. Manual "1. / 2. / 3." prefixes dropped; the styling
carries the hierarchy.
Both PhonePe heroes deleted. The banner slot was always meant for a
walkthrough VIDEO (study.walkthrough outranks heroImage, so the clip drops
in with no config change). A still was tried and rejected: it showed the
conversion screen, which Price transparency already argues — the page opened on
its own punchline. Hero-less pages get case-hero--solo: 24px → 80px under
the positioning line, which was otherwise equidistant between the title and the
first H2 and read as a subtitle of the section.
Read-more rail gains a thumbnail fallback (firstFigureImage): a project
with a case study but no TILE_PREVIEW shot now borrows the first still its own
study renders, so no card sits blank beside siblings that have one. Video
figures skipped — a clip has no still to lend.
Transaction History re-exported: the old file was 789px wide rendering into a
720px column — 1.1× density, visibly blurry on any retina display. Now
1440×2373, an exact 2× match, alpha intact.
2026-07-21 · UPI International gets its UX story; figures learn viewport pairs and transparency
Deploy: anirudhux-gvuvn23ug-anirudhux.vercel.app
UPI International rewritten around the actual UX decisions. Overview merged
with the friction framing (cash / forex card / hidden markup, and the mental
math underneath all three). New Price transparency section on the
conversion screen — dual currency, live rate, the guaranteed INR figure before
the PIN. Activation absorbed the discoverability material: contextual
prompting, one-tap, a validity that expires by itself. "Where it works" was
DELETED — its NRE/NRO material belongs to a different product, and leaving it
conflated two projects on one page (Anirudh's call).
Three new figures, all transparent cut-outs: forex-anxiety (Price
transparency), activation (Activation), and UPI Lite's ftux (UX
Implementation). Plus pan on the 2720×900 FTUX composite — fitted to the
column at 390 it rendered ~129px tall with unreadable screens; it now runs
70svh in a horizontal scroll strip, the same treatment Constella's views trio
uses.
Figure.transparent — the olive-plate fix..case-figure img paints a
family-tinted card (--tile 7% over the warm #fffdf7, MEASURED
rgb(239,241,233) against a white page). Correct for an opaque screenshot;
wrong for cut-out artwork, where it fills every clear pixel and reads as a
dirty green slab. transparent: true drops the plate and the hairline.
Specificity trap: the dark plate is a separate [data-theme="dark"] .case-figure img rule at (0,2,1) — the override MUST sit after it, or you fix
light mode and ship dark still tinted.
Figure.mobileSrc — viewport pairs for stills. A <name>-mobile beside a
figure now pairs on width exactly as <name>-dark pairs on theme: both
render, CSS shows one, wide is the SSR default. Built because forex-anxiety is
1080×560 landscape and 420×750 portrait — re-composed, not scaled, so no
amount of CSS gets from one to the other.
.case-more-cta label is "Read More"; docs pass corrected CLAUDE.md's
routing section (it still described /ai · /work · /community as redirect
shells), and ARCHITECTURE/DESIGN gained the route map and the affordance table.
Two enforcement hooks land (.claude/settings.json + .claude/hooks/): a
Stop hook that blocks responses ending on unasked-for git status, and a
PostToolUse hook on preview_start that requires two fixed-viewport tabs
(desktop 1440×900 + phone 390×844) on every server boot. Both exist because
the rules they enforce had failed repeatedly as memory alone.
2026-07-21 · Transaction History goes transparent; the Read-more CTA stops breaking
Deploy: anirudhux-8x4dlvgry-anirudhux.vercel.app
The Transaction History asset is now genuinely one file for both themes.
Anirudh re-exported it with a transparent background (789×1300, replacing the
opaque 1150×2302); re-encoded with cwebp -alpha_q 100 -exact, which stores
the alpha plane LOSSLESS. Verified per-pixel rather than by corner sampling:
source and output both report 45.1% fully-clear and 5% anti-aliased pixels,
i.e. the channel survived byte-for-byte. .case-figure carries no background
in dark, so the page ground reads straight through.
Method note worth keeping: the first check sampled four corners and one
edge row and concluded "no transparency" on an image whose clear area is its
BODY. Corner sampling is not an alpha test — scan the whole buffer.
.case-more-cta became an inline-flex unit. The arrow was dropping to its
own line under "Read case study" even though the rule already had
white-space: nowrap — nowrap can't help when the SVG is a separate inline
box, because the break opportunity sits BETWEEN the text node and the glyph.
display: inline-flex + gap: 4px removes the opportunity entirely, so a
future longer label can't reintroduce it. Label shortened to "Read More"
(Anirudh's call). Verified single-rect at 1440 and 700.
Blob store tidied earlier in the day stays at 8 objects; no media changed here.
2026-07-21 · UPI Lite case study; NDA becomes a row state; redirect rows get the arrow
Deploy: anirudhux-i3dbs45mk-anirudhux.vercel.app
The second PhonePe case study is live at /work/phonepe-upi-lite, wired
through the real system (projectPages + generated_pages +
LIVE_CASE_SLUGS) rather than hand-rolled — arc, corner icon, TOC, Contact
band all inherited. Sections: The Problem Space · Core User Journey · PhonePe's
UX Implementation · Transaction History · Key Outcomes.
The walkthrough keeps its AUDIO. Four cuts (light/dark × desktop/mobile)
re-encoded 67 MB → 6.0 MB and self-hosted on Blob. Unlike every other clip on
the site these carry an AAC track — it's the narrated "audio trial" — so the
audio was preserved at 128k instead of stripped, and CaseFigureVideo's
controls (never autoplay, never muted) is doing real work. Trap:vercel blob put appends a random suffix REGARDLESS of
--add-random-suffix=false, so these urls are pinned in UPI_LITE_CUJ and a
re-upload mints new ones that must be pasted back. (The International set
predates this and keeps bare names.)
NDA is its own row state, deliberately NOT a reuse of locked. "Not
written yet" is a promise that eventually lands; work under NDA never will,
and collapsing them would make the grid promise something it can't keep. B2B
Payment Gateway and ExpressBuy now render a lock + an NDA chip and dropped
their play stub, which had been advertising a walkthrough that is never
coming. The chip is family-tinted (--tile) so it needs no new token; dark
takes the stronger mix, the same correction the testimonial zebra rows needed.
Row glyphs are decided by RULE, not per row: any row with an href gets
the redirect arrow. "This takes you somewhere" is equally true of Nutella, UCI
and both UPI case studies; play now means only "footage, no page yet". This
intentionally changed UPI International too — same case, aligned rather than
patched one row at a time.
Blob store tidied: 12 → 8 objects (four orphans from a re-upload deleted after
matching byte sizes, then all four live variants re-verified 206).
Known debt: the case hero is a PLACEHOLDER (Contraire's shot, picked so the two
PhonePe pages don't open identically). The Transaction History asset is one
file for both themes at Anirudh's call — its source PNG is opaque white, so it
reads as a light screenshot on the dark page; a transaction-history-dark
dropped beside it would pair automatically via assetPath.
2026-07-21 · Every lens view gets a real address: /ai, /work, /community
Deploy: anirudhux-lqibiurnz-anirudhux.vercel.app
The redirect shells are gone./ai, /work and /community used to be
three-line documents that bounced to /#all-*; they now SERVE the bento.
app/page.tsx's client body moved to components/HomeView.tsx behind a
view prop, and four thin route files render it — so the exported HTML at
/work already carries the All lens on the Work tab. No redirect hop, no
post-hydration correction, no flash. The T1 /work plate finally names a real
address instead of labelling a parked one, and the three routes drop
robots: noindex for their own titles + canonicals.
syncHash → syncPath. Flipping a lens or tab rewrites the PATH with
replaceState — same-document, no reload, no history growth (verified:
history.length unchanged across flips), and a refresh reopens the same view
because the static export has a real document at each path.
Legacy /#all-* addresses still resolve, and self-heal. The boot effect
reads the hash, applies the view, then rewrites to the canonical path, so the
hash form dies out on use instead of lingering in bookmarks forever. Bare
#all resolves to /ai — its canonical form is the tab the All lens opens
on, not whatever tab React happened to be holding. (One cosmetic tell: a
legacy load keeps /'s <title>, since it IS /'s document.)
The trap this change walks straight into:template.tsx exempts the
homepage from the .page-enter wrapper because that wrapper's transform would
become the containing block for the homepage's fixed folds — collapsing the
bento grid and un-fixing the phone's dot ground. Three new routes render that
same homepage, so the exemption now covers all four addresses. Verified at
375px: position: fixed held across a 600px scroll with zero transform
ancestors.
Smoke gate tightened — the three tab routes must now show
.lens-bento .bento-stage, so a regression back to a redirect shell (or a
Highlights-seeded route) fails loudly instead of passing on nav elements
alone. 24 routes × 3 viewports × light/dark green; /#all-work kept in the
route list as the legacy-address regression guard.
Noted, not fixed: the Tab union still carries a vestigial "About" (absent
from NAV_TABS, meta-only template, unreachable from the switch). PATH_FOR
is Partial on purpose rather than inventing an address for it.
2026-07-21 · UPI International case study; walkthroughs self-hosted on Vercel Blob
Deploy: anirudhux-hl8tlw4hr-anirudhux.vercel.app
The first PhonePe case study is live at /work/phonepe-upi-international,
rendered by the REAL CaseStudyPage — registered in projectPages +
generated_pages/, positioning filled in content.ts, slug added to
LIVE_CASE_SLUGS. A hand-rolled standalone route was built first and deleted:
it silently dropped PageAmbience (family arc + project icon), the Read-more
rail and the tools/live gates. Replicating a case study means wiring it into
the system, never rebuilding the markup by eye. The Work tab's UPI
International row now links to it (internal hrefs navigate in place; external
product/report links keep target=_blank).
Section video.Figure gained video — one url, or the light/dark ×
desktop/phone set. New client component CaseFigureVideo picks the variant by
theme + viewport (CardVideo's pattern: mount gate for hydration, key={src}
for a clean remount). This lets a walkthrough sit under its own heading instead
of being forced into the top banner slot.
Video hosting moved to Vercel Blob (store anirudhux-media, public). The
four UPI International cuts came in as 88 MB of HEVC — Safari-only — and ship
as 10 MB of H.264. Raw screen-capture sources are gitignored; only the Blob
URLs live in code, so the repo stays lean. Blob's 5 GB free tier makes storage
a non-issue; the constraint that actually matters is the 100 MB Hobby
CLI-deploy cap, which is exactly why videos can't sit in public/.
All site videos drop their download affordances — controlsList="nodownload noplaybackrate", disablePictureInPicture, right-click suppressed. Friction,
not protection: the file is still reachable via DevTools or the direct URL.
Known debt: the case hero is a PLACEHOLDER (Constella's shot); transparent-
background video is off the table (mp4/H.264 can't carry alpha) — the
sustainable path is the light/dark × desktop/mobile variant model now in place.
Perf: ShowcaseFold feed pipeline memoized (was rebuilding every render incl.
the ~156 loader ticks). Cross-browser: paired -webkit-backdrop-filter on the
showcase CTA. Stale CLAUDE.md notes corrected (BackLink, CardVideo debt).
Verified live: every case page's images/videos decode + serve 200 (webp/mp4),
homepage loader + 5 walkthroughs load, no console errors. No visible change —
same site, ~half the bytes.
2026-07-19 · Work tab rebuilt around umbrellas; interfaces become phone sub-tiles
Deploy: anirudhux-aw9eifdr0-anirudhux.vercel.app
Work is now four tiles — Ennoventure and PhonePe as umbrellas, Design System
as an offshoot, Product & Design Research as the cross-company tool. The
three-sides-one-system story is told by structure, not a case study.
On phone each umbrella folds its interfaces into an inset composite: AI-style
cards (40% thumbnail + play stub + squeezed copy), full-bleed rows inside one
container with inset accent separators — white fill, family colour in strokes
only. Text hierarchy: section 20 › interface 16 › note 14. Design System folds
into Ennoventure as a phone-only locked card; stays its own tile ≥601.
Design System joins the AI reveal mechanism (tablet shot); the Shape /
Design-System tablet shots are nudged (object-position) to line up with the
laptop screens above/below.
Tablet fixes: slimmer footer, switch pill clears the last rows, top gap closed.
KNOWN DEBT (shipped intentionally): every Work thumbnail is a PLACEHOLDER
(AI product mockups standing in) and the video walkthroughs are stubs — both
swap for real assets when they land. Owner shipped knowingly on the low-traffic
staging URL ahead of the anirudhux.com move.
2026-07-17 · The OG card goes light; the pill tooltips stop clashing
Deploy: anirudhux-ja0wxcho4-anirudhux.vercel.app
The share card is now LIGHT (owner's call) — same composition and IA, the
site's own light standards: white ground with the faint COOL petrol tinge
at the edge (.showcase-fold's recipe), --ink on every primary line,
tangerine #c9530c on SEEKING, copper #7A4420 dots at 26%. Contrast
measured on the real composites: 17.32 / 6.86 / 4.44 / 5.22 / 4.18 — all
pass. Still legible at a 160px thumbnail.
The avatar's monotone glow becomes a halo sweeping all four family hues.
Two lessons in the file: the raw tokens (L≈0.30) go grey when blurred on
white, so the hues are lifted in oklch — same L, same C, family hue; and
the sweep MIRRORS (petrol→forest→moss→tangerine and back) because the only
pair a one-way conic leaves adjacent is tangerine/petrol, which no
interpolation space crosses cleanly. Chroma is the taste dial: 0.115 made
every hue measurably land and read as a cartoon rainbow — it ships at
0.055. Verify that one by eye; the saturation numbers all passed.
Tooltip clash fixed (regression from 089a9da, same day): .is-open was
added to the ≥821 reveal, so a desktop click pinned a tooltip that survived
mouse-leave — hovering the next pill painted a SECOND 288px card 150px into
the first, and only an outside click could clear it. The two reveal
mechanisms are now partitioned by the same 820px line the CSS uses and
never coexist: ≥821 hover/focus, ≤820 tap. Button semantics ride the same
gate (role/aria-expanded were lying on desktop).
2026-07-17 · Hareesh's testimonial lands
Deploy: anirudhux-60frjtqs9-anirudhux.vercel.app
New testimonial from Hareesh Nakkerthi (PM, Ennoventure), placed third —
after Veena — in both the /hire-me list and the mosaic feed. Paraphrased
from his LinkedIn recommendation; marker phrase "thinks sideways".
His closer was cut deliberately: it collided with Chetan's opener ("Any
team Anirudh joins simply gets better"). No LinkedIn link on the name —
the URL wasn't to hand, and the card renders fine without one (Chetan's
does too).
Avatar cropped from a full-body reference to head-and-shoulders, matching
the other avatars' framing: 800×800/172KB → 200×200/12KB.
Side effect of INITIAL = 4: Srinivasan now sits behind "Load more".
2026-07-17 · The switch pill tracks the footer instead of dodging it
Deploy: anirudhux-9kcczazn5-anirudhux.vercel.app
The phone/tablet switch pill now rests 16px off the screen's edge. It
had been parked at bottom: 84px — never a rest position, just a constant
sized to the footer's height, which bought one scroll position by floating
the pill high over the feed at every other one. It shipped, and it read as
broken on a real phone.
The collision moves to useSwitchLift() (app/page.tsx): it watches the
footer's top edge and lifts the pill only as the footer arrives, holding
the same 16px gap, then riding it up 1:1 with the scroll. Verified on
production at 390 — 16px to the edge throughout, 16px to the footer at the
end, continuous through the hand-off.
iOS collapses its URL bar without firing a window resize, so
visualViewport.resize re-measures too; a ResizeObserver on body
covers lens flips, tab switches, and late-loading images.
2026-07-17 · The blurb learns its column's ruler; pills go tappable
Deploy: anirudhux-flv97cxma-anirudhux.vercel.app
Homepage layout re-railed: absolute 35/65 column split (gap carved out
before the ratio), 32/64/32 rhythm (--lens-gutter: 32px, --lens-gap: 64px), and the whole container capped at --lens-max: 1800px via
--rail-pad — ultrawide gets margin, not drift.
The blurb's type now scales on the COLUMN's ruler (container queries, cqi)
instead of the viewport's — 1280's proportions hold to the cap; the 252px
of dead air at 1920 is gone. Absolute px bounds converted to rem (root was
always the browser-default 16px; user font-size prefs now respected).
Bio wraps at most twice and only before "since 2015" — the hardcoded
<br> after "designing &" is gone; two nowrap segments own the break.
Pills scaled ~8% down so the row always ends inside the bio's first line.
Company pills are tappable on phone/tablet: same tooltip, tap-to-toggle,
outside-tap/Escape closes; the card anchors centered above the pills ROW
(a pill-anchored 288px card would cross the intro column's clip at 390).
2026-07-17 · The slab wears the switcher's hairline
Deploy: anirudhux-qubpdxyve-anirudhux.vercel.app
The fused Highlights slab's border + painted grout now use the nav
switcher's stroke recipe verbatim (hue 30%, 0.5px) — owner's call: the
switcher treatment is the law. Supersedes the 55% grout A/B from 07-12.
The real fix was compositing: the grout paint ran UNDER the border and the
perimeter stacked to ~51%. background-clip: padding-box keeps the paint
in the seams only; the edge is the bare hairline. Both bands (≥901, 601–900).
2026-07-17 · Constella case study rewritten; the register becomes law across every case page
Deploy: anirudhux-pg99smc51-anirudhux.vercel.app
Constella's three source MDs rewritten from a full hands-on pass of the live
app and a real exported HTML file: the builder-at-altitude structure (why /
what / how / decisions / outputs / takeaway), the three refusals, the
keyhole framing, "Comparing visualizations" with a spliced sunburst-graph-
tree composite (horizontally pannable at 70svh on phone/tablet), and a
four-way outputs section. "It's built to leave" is banned and gone.
Contraire fully rewritten in the same register — context-free exhibit
quotes deleted, jargon out, six plain-speech stage labels, walls-as-design
takeaway. Anatomy and Shape de-flourished after a cold-read audit killed
their self-quotes; PR;SOS meta deduped; generic section headers replaced
with idea-carrying ones across all three.
Section-hero figures now lead their sections (placement bug: heading-keyed
figures appended after prose); fresh Constella stills incl. sunburst/tree,
outline retired; the stills capturer gains --dark and theme forcing.
2026-07-17 · abaf732 — One clock for the homepage hue; colour census
The homepage hue cycle runs ONCE on body:has(.lens-topbar) — was four
independent per-element clocks (two at 9s, two at 18s), which is why the
wordmark and page visibly drifted apart.
Every dark petrol stroke (slab border, grout, card hairlines, switcher
border/divider, phone pill) now rides the live hue instead of fixed petrol.
The switcher's muddy-brown dark surfaces became hue-derived — same
lightness, breathing with the page.
docs/COLOR.md: the full colour census with measured WCAG ratios; /bench
gains the read-only "Parked" card (PARKED in lib/curation.ts).
All four Constella takes re-recorded at 1920×1080 off the real host
(constella.anirudhux.com), walking the new app (Sunburst · Tree · Details).
Light-MOBILE recorded for the first time.
The recorder itself fixed: dead host, wrong frame height, silent dark-theme
takes, and a stale-temp-dir bug that once shipped a portrait take as the
desktop file.
Case pages: the Visit-live CTA retired — the title's ↗ is the one live link.
2026-07-16 · 3187a91 — Contact becomes a door; petrol slab deleted
The Highlights Contact band is gone; a small Contact CTA (bottom-left
desktop, under the pills on tablet, none on phone) opens the same form in a
native dialog. Two doors, two intents: Hire-me = pitch, Contact = direct line.
.is-petrol and the whole per-host colour machinery deleted — the band is
always the host page's colour now.
Two layout bugs fixed: gitlab-talk's implicit second grid column (prose
starved to 110px on phones) and the .case-arc 100vw scrollbar spill that
side-scrolled every case page by 7px.
2026-07-15 · c466c2d → 1dab8d8 — the OG share card, twice
First: a designed card replaces the stale bento screenshot.
Then the phone-first rework: name + role + Seeking + avatar at sizes that
survive a WhatsApp thumbnail; anirudhux.com · Ex: footer line.
Hire-me contact form: Web3Forms delivery (public-safe key, honeypot +
time-trap + server filtering), no name field, forest-green focus.
Contact becomes the site's closing band — collapsed teaser, measured
heights, its own dot field. Petrol slab scoped to Highlights only after it
wrongly went sitewide.
Testimonials: zebra tint + "Load more" past 4. Previously-at pills with
company tooltips. The smoke suite gains the overflow gate.
2026-07-13 — tablet joins the desktop system (3 commits, 24ffcff → e61e47c)
Tablet = the phone's header on the desktop's body: bare centered T1 over a
dot ground, desktop tiles with icons, curated <br> breaks.
Nav pill + wordmark polish: 46px switch, eased label wipe ≤600, grown
wordmark tap target. Two orphan case pages removed.
Hire-me refit (avatar hero, authored testimonials), Work tab dressed,
footer flows at scroll end.
2026-07-10 — the navigation contract (26 commits, f294a0a → cc1fa8c)
View state became NAVIGATION state: lens/tab addressable in the URL,
Back restores the exact view, loader skips history returns pre-paint.
Flat nav + hover-reveal tiles; unified switcher pill with tab icons;
Constella leads AI in both lenses (the cross-lens consistency RCA).
Tablet choreography rounds (meta card, arc, packing rule), DARD case study,
listing routes park as redirects, hire-me dialog hardening.
2026-07-09 — the spin-out: lens homepage to production (29 commits, 7e9b7e0 → 179bd5d)
final-folio spun out of mosaic's lens-switch branch and promoted to
production the same day.
Lens v1→v4 in one day: Highlights ⇄ All under a fixed pivot, per-letter
identity type-in, sequenced switch unfold, meta-card morph.
The identity state machine, Hire Me modal, frost-on-nav, the 28px rails,
the slim one-line footer.
lib/curation.ts + /bench born (owner control surface), dark-mode a11y
overhaul, theme/viewport-aware walkthroughs, one chrome system sitewide +
legacy purge.