anirudhux
Open to new opportunitiesHire me

Changelog — production pushes

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).


2026-07-23 · Analytics: GA out, PostHog in

Deploy: anirudhux-f1nf2cd2d-anirudhux.vercel.app → anirudhux.com

  • 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

Deploy: anirudhux-j3njvbewt-anirudhux.vercel.app → anirudhux.com

  • 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

Deploy: anirudhux-7vbki33f0-anirudhux.vercel.app → anirudhux.com

  • 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

Deploy: anirudhux-c8cq95lm8-anirudhux.vercel.app → anirudhux.com

  • 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

Deploy: anirudhux-h0wm0xugg-anirudhux.vercel.app → anirudhux.com

  • The slim footer is dead (Anirudh: "which sane person would maintain different types of footers?"). Every page — case studies, placeholders, /changelog, homepage — closes on the sectional footer: brand stack + signature lines, Highlights/Explore/Connect, © + theme switch. The sectional prop is gone; the CSS moved off the homepage's .lens-footer scope to doubled-class selectors at the same weight (homepage renders pixel-identical). The wash wears the HOST's family colour — copper/moss/ forest per case family via the new accent prop, tab colour on the homepage, petrol fallback elsewhere.
  • 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

Deploy: anirudhux-3n0zv66w6-anirudhux.vercel.app → anirudhux.com

  • 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

Deploy: anirudhux-p1g8zknu6-anirudhux.vercel.app → https://anirudhux.com

  • 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). siteUrlhttps://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.

2026-07-22 · Housekeeping deploy: resume drafts stay owner-private

Deploy: anirudhux-8b891yzsu-anirudhux.vercel.app

  • 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.
  • Brand column restructured: portrait + bio line out (the T1 one viewport up already introduces); wordmark + signature stack instead — ❤️ Crafted in Bangalore · 🤖 Shipped with AI in the loop (Built-with tooltip rides it, left-anchored — centered it clipped at the rail). © sits on the base strip in line with the theme switch. "Book a call" replaced by the real Contact dialog (link trigger); Explore's Tools anchor became the dialog.
  • 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.
  • syncHashsyncPath. 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 affordancescontrolsList="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.

2026-07-19 · Stress-lab: −54% asset weight, dead-code purge

Deploy: anirudhux-9paahe0dj-anirudhux.vercel.app

  • public/ 116MB → 53MB. All 76 /projects images → WebP (resize ≤2400px, q82); the case-study figure/hero/poster resolver is now format-agnostic (assetPath, webp-first, raster fallback), so future assets swap freely. null-detector case page dropped 14MB → 0.8MB.
  • Walkthrough mp4s re-encoded at CRF 28 (were over-encoded): video 53MB → 35MB.
  • Orphans deleted: constella/walkthrough.gif (5.2MB), null-detector/weapon.png (2.7MB). Both GIFs retired (512.gif → lossy animated webp; loop.gif poster → static webp frame).
  • Dead code removed: BackLink, CopyEmail, Glyphs, UseTransform, ZoomStage, DotField (+ the motion dep, 4 pkgs pruned). Runtime deps 6 → 5.
  • 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).

2026-07-17 · 34e0975 — Constella walkthroughs re-shot; bench edits URLs

  • 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.
  • /bench grows per-project live-URL editing (in-place live: rewrites in lib/content.ts, bare-host normalised).
  • 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 · c466c2d1dab8d8 — 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.

2026-07-14 — contact ships end-to-end (6 commits, 2387df1739db49)

  • 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, 24ffcffe61e47c)

  • 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.

2026-07-12 — desktop-lab ships (4 commits, 5ca9f4e029b7f9)

  • Highlights fuses into ONE slab: 1px grout seams, container border + radius, fixed petrol wash over footage, hero +20%.
  • Tiles: rest fill becomes a paper→family-tint wash; T1 sheds the tile look entirely (wall label on a dot ground, mono /route plate).
  • Constella moves to constella.anirudhux.com — first tenant of the subdomain incubator.

2026-07-11 — mobile-lab ships + the perf pass (8 commits, bd270baeb709ea)

  • The phone rethink: centered header bands, one fused frosted card, viewport- fixed dot ground, page-load nav rises. Highlights joins the same language.
  • Perf: ~12MB shed — webp everywhere, phone footage truly retired.
  • Hire-me refit (avatar hero, authored testimonials), Work tab dressed, footer flows at scroll end.

2026-07-10 — the navigation contract (26 commits, f294a0acc1fa8c)

  • 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, 7e9b7e0179bd5d)

  • 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.