anirudhux
Open to new opportunitiesHire me

Changelog: production pushes

Every entry is a cbv: commit, GitHub push, vercel --prod on anirudhux.vercel.app. The "cb" is historical from Codeberg; the ritual name stayed on the migration to GitHub, 2026-07-30. 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 gets written during the cbv itself. Gates pass, then deploy, then the entry gets the deploy URL, then the commit takes the entry with it. Nothing ships without a line here. The seed below (2026-07-09 to 17) was distilled from the commit history; pre-17 deploy URLs are not recorded (Vercel's dashboard maps them by commit metadata).


2026-08-22 · The agent-readiness gaps close

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

  • An external agent-readiness report brought five findings; two were real. The homepage now ships a JSON-LD Person block (name, role, employer, sameAs to LinkedIn, GitHub and X; facts mirror content.ts), and a real 404 page with the site chrome points agents at /sitemap.xml and /llms.txt. The status code was already a true 404.
  • llms.txt gains a "When to use this" section between Best fit for and Summary, generated with the rest of the file.
  • Dismissed with evidence: the no-JavaScript check (the export already serves the H1 and ~3,460 characters of text in raw HTML) and the Vary header advice (the site does no Accept negotiation).

2026-08-18 · Dialog focus seats on the panel, not the close button

Deploy: anirudhux-21uplsb2h-anirudhux.vercel.app → anirudhux.com

  • showModal() spec-focuses a dialog's first focusable, the close button, and Safari paints its focus ring on that: every dialog opened with a highlighted ✕ (my catch, on Hire Me). All four dialogs (Hire Me, Contact, Tools, Video Overview) now seat the opening focus on their panel (tabIndex −1, focused after showModal, no outline for it). Keyboard flow is unchanged: focus starts inside the dialog, the first Tab reaches the close button, Escape still closes.

2026-08-12 · The GitHub heatmap joins Hire Me

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

  • A GitHub contributions section in the Hire Me dialog, between Testimonials and Tools: the pulse-embed heatmap (one iframe per theme, swapped by data-theme like the hero stills), a credit line under it ("Visualization in Pulse by Sooraj Nair.", both names linked), and a GitHub entry in the dialog's index. /hire-me#github lands on it.
  • The smoke gate blocks third-party requests by design, so the gate sees the section without the pixels; the heatmap comes from pulse-embed.vercel.app at view time.

2026-08-11 · The video doors close while the clips get replaced

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

  • The homepage "Overview" CTA and every case page's "Summary" CTA (index door and floating pill) are hidden behind one flag, VIDEO_OVERVIEW_DOORS_ENABLED in lib/curation.ts. The Sarvam-voiced clips are being replaced with my own narration; the dialog, reel-data, and the VIDEOS curation stay intact, so re-enabling is one line.

2026-08-11 · UPI International's core journey, re-cut and cache-proof

Deploy: anirudhux-2ck7sgcm5-anirudhux.vercel.app → anirudhux.com

  • I re-cut all four Core User Journey videos (light/dark × desktop/mobile, ~37–39s from 45s). They ship on new -v2 Blob pathnames: the store serves with a 30-day max-age, so an in-place overwrite never reaches a browser that cached the old file. The lesson is a comment in project-pages.ts now: a re-cut takes a versioned pathname, always.
  • Origin copies updated in private-refs/sources/blob-archive/.

2026-08-11 · The ledger reads in my register

Deploy: anirudhux-472se04r6-anirudhux.vercel.app → anirudhux.com

  • I had every entry in this file rewritten, masthead to the 2026-07-09 seed: em-dashes out, bold fragment labels out, the pivots rephrased, the ledger speaking in first person. Every fact, deploy URL and measurement kept. /changelog serves the rewrite now.

2026-08-11 · Same overlay on the hero as on every tile

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

  • The lead card had its own mesh and scrim rules, tuned for Constella's dark graph still; deleted them. The hero now uses the same mesh, scrim, and hover as every other tile. UPI International is the reference.

2026-08-11 · The hero shows UPI Lite's own screens, uncut

Deploy: anirudhux-9onh89y7d-anirudhux.vercel.app → anirudhux.com

  • HERO_STILL still pointed at Constella's images after the hero change; it now points at UPI Lite's. The coupling with HIGHLIGHT_HERO is documented in lib/curation.ts.
  • New hero image: ftux-hero.webp, four screens cut from the ftux strip and padded to 1880×1226 to match the hero box's aspect. Nothing gets cropped.
  • Deleted the scale(1.45) zoom on .showcase-card-poster; it existed to crop Constella's app chrome and clipped every other hero's headroom.
  • Highlights order from the bench: UPI Lite · UPI International · Constella · Contraire · GitLab Talk · Transform Design · Shape of portfolios.

2026-08-11 · UPI Lite takes the hero

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

  • I re-curated Highlights from the bench: UPI Lite leads the feed and takes the hero banner; Constella moves to second.
  • The Video Overview opens on UPI Lite now. The rail order: UPI Lite · UPI International · Constella · ExpressBuy · Contraire · PhonePe Cart · Shape of portfolios · Design System.

2026-08-10 · The case-page summary keeps to its own clip

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

  • The Summary door on a case page opens a single-clip dialog now: no clip rail, titled "Summary". A reader on UPI Lite gets UPI Lite instead of seven doors out of the page. The player spans the full width in this mode.
  • The homepage door is unchanged: "Video Overview", the full rail, browsing across all eight clips. One shared dialog, one flag (openVideoOverview(slug, { single: true })) set by the case doors.

2026-08-07 · The dark door dims, the index draws its arrow

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

  • In dark mode the Video Overview door drops the white fill for the petrol wash (24% mix); the secondary pill no longer outshines the primary Contact below it. Light mode keeps the white ground as specced.
  • Index headings render text arrows as the drawn ArrowRight glyph (Cart's "User stories → structure"): one arrow grammar with the Read More cards.

2026-08-07 · Summary doors on every clip page, eight indexes cleaned

Deploy: anirudhux-98fq4bumh-anirudhux.vercel.app → anirudhux.com

  • Every case page with a clip has a Summary door ("▶ Summary · m:ss"). On desktop it goes under the sticky section index: the rail stops at the last section, the door follows a 56 step below at index-size type. On tablet and phone it is a centered compact floating pill that hides past the last row of text. Family wash from --tile via the NDA-chip recipe; it opens the Video Overview on that page's own clip. Clip-less pages get no door; membership is decided at build from VIDEOS plus the reel index.
  • Six indexes restructured to my shapes (Constella, Cart, ExpressBuy, Shape of Portfolios, Contraire, plus renames): folded topics as sub-heads and every figure key following its section. Design System, UPI Lite and UPI International signed off unchanged.
  • The reel timelines now hold the combined audio file per combo; Constella's retired four-voice files are gone from reel-data.

2026-08-07 · Sound returns, decided by the client

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

  • The store is back (the Pro upgrade lifted the suspension) and the 96 combined audio files are uploaded. The case-page walkthroughs healed with no deploy since their URLs never changed.
  • The kill switch is deleted. Sound is a client decision, per clip: the viewer probes the combo audio before mounting and plays captioned silent video when the store fails to answer. An outage degrades by itself and recovery is automatic; no flag, no deploy in the loop.
  • Verified on production: Constella plays with voice from the store, and a clip switch stays paused per the no-auto-play rule.

2026-08-07 · Reel sound off while the Blob store is suspended

Deploy: anirudhux-86bn3wgae-anirudhux.vercel.app → anirudhux.com

  • The audio store hit the free tier's operations cap (2,952 uploaded files against 2,000 included operations) and Vercel suspended it. Uncached reads 403 ("Your store is blocked"), so clips went silent unevenly.
  • Kill switch until the account gets sorted: REEL_SOUND_ENABLED = false in lib/reels.ts removes every audio element from the composition. The reels play as captioned silent videos and the site sends the store nothing.
  • Flip the constant and cbv to restore sound once the store resumes.

2026-08-06 · The Video Overview: eight narrated reels in six languages

Deploy: anirudhux-5a2y8ddvk-anirudhux.vercel.app → anirudhux.com

  • A new door on the Highlights foot ("▶ Video Overview · 23 min", secondary pill stacked above Contact, both column-wide) opens a two-panel dialog: the live player on the left with the project name and its positioning copy, the eight clips as chapters on the right. The structure mirrors the Hire Me dialog; desktop first, the mobile ingress arrives with the mobile design.
  • Each clip speaks six languages in two voices (Sunny default), with speed control. Timing is measured from the real audio per sentence, so a language or voice switch stays on the same sentence. Audio streams from Vercel Blob (2,952 files, 177 MB); the repo holds only timelines and manifests, and the player loads lazily so the homepage bundle stayed 139 kB.
  • This dialog is the one exception to the site-wide force-mute: narrated clips play with sound at the visitor's own play press, never automatically. Closing the dialog stops the voice on the synchronous close path.
  • Curation joins the bench: a VIDEOS set and order in lib/curation.ts drives the rail (first = opener), editable on /bench like HIGHLIGHTS.

2026-08-05 · llms.txt names the page as well as the product

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

  • Agents were 404ing on guessed URLs. Each heading had a title and the external product link only, never the page on this site, so an agent that wanted the case study slugified the title: "Anatomy of a Lie" became /ai/anatomy-of-a-lie and 404'd, because that project's slug is null-detector. I watched it happen live. No redirect was involved; the URL was invented because nothing published the real one.
  • Every heading now leads with the canonical page, then the live product where one exists. The sitemap had the right paths all along but shares no key with llms.txt, so it could never close the gap.
  • The same trap covered two other title/slug mismatches: UCI: Counterfeit Study (uci-certification) and Nutella 400g (nutella-400g).
  • Verified after the build: all 14 canonical URLs in the generated file return 200.

2026-08-05 · Fluid sizes become tokens, and a gate that keeps them that way

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

  • The 30 hand-tuned clamp() sizes are now 21 named tokens declared in one block with their px range at 390 and 1440 written beside each. They had accumulated across 19 commits from 2 to 26 July, each authored for one element and never compared with the rest. Below roughly 900px nearly every curve rests on its floor, so phone and tablet were already fixed values and the fluid behaviour is a desktop concern; that is visible in one place now.
  • Removed 21 dead rules. Nine classes no component emits any more: sib-name, sib-pill, sib-cta, sib-availability, mosaic-vnav-item, mosaic-card--feature, route-heading, listing-title, bento-loader-count. Checked against the markup rather than against whether they happened to render in a sample.
  • The smoke suite gains a type gate. The build now fails on a raw font-size or font-weight in globals.css, and on any inline fontSize/fontWeight in a component. The second case is the one that mattered: the tile titles had their size inline, which outranks every stylesheet rule, so the type pass could never reach them and nothing said so.
  • Verified against an 84-point baseline across six routes and six widths, before and after each step: zero differences, twice.
  • The Nutella thumbnail is a real asset now, recaptured from the report at 1.8:1 rather than held together by a cover-crop rule. It renders the same height as its neighbours at every width, on every surface.

2026-08-05 · UCI thumbnail, two renames, and the broken research images

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

  • New UCI thumbnail from my render, cropped and zoomed 1.33x so the white above and below the frame tube balances on the left edge (350 against 378, from 812 against 436). One file feeds every surface, verified at 390, 768 and 1440.
  • Two rows renamed on every band: UCI: Counterfeit Study and PhonePe: Consumer Study '22. Both had a separate phoneTitle fork; one title works at every width now, so the forks are gone and the UCI kernel title in content.ts agrees with the config again.
  • research.anirudhux.com/uci images were failing to load. The files were fine; the path was wrong. /uci serves the page without redirecting to /uci/, so the browser resolved the relative assets/… against the root and asked for /assets/trek-stickers.png, which 404s. The five UCI images and Nutella's jar illustration are root-absolute now and resolve with or without the trailing slash. Deployed separately to the research project.

2026-08-05 · The switcher moves to the top of the phone

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

  • The tab switcher docks under the wordmark bar. Readers called the old floating pill jittery, and the measurements agreed: it dodged the footer, so its position was a function of page length. At the end of scroll it measured 16px from the bottom on Highlights, 86 on Work, 281 on Community and 288 on AI, and on AI it started moving before the first screen was read. It now holds one position on every view at every scroll offset, gets out of the way while you scroll down, and returns the moment you scroll up.
  • Swipe changes tabs. Left goes forward, right goes back, through the same path a tap takes. Gestures starting at the left edge are ignored (that is Safari's back swipe), as are diagonals and anything under 60px.
  • One blanket 24px gap governs the top of the phone page: under the wordmark bar, under the switcher, and under the last card. The 84px the stage reserved for the pill that used to float there is gone.
  • One card type across all four tabs: 18/800 titles, 14/400 descriptions, which is what tablet already ran. The tile titles could never be restyled before this: their size was an inline style, and inline outranks every rule, so the type pass could never reach them. They read from CSS now.
  • AI joins the phone card grammar: Anatomy of a Lie skips the band, and the three that remain stack and centre with the whole device shown, the same numbers the Highlights feed uses for the same cards.
  • The hover tint is gone on phone. It fired on tap and stayed, so the last row you touched kept looking selected.
  • Centred copy balances now: the Highlights ledes were -webkit-box for a clamp, which blocks balancing outright; the clamp came off since every lede fits in three lines.
  • Cleanup: 13 duplicate declarations resolved at source, three override rules deleted, and the dead side-by-side row flex props removed.

2026-08-05 · A type scale in rem, and the dead wrapper it uncovered

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

  • Type is tokens now. Eleven size tokens and five weight tokens in :root, baseline 16px = 1rem, and all 194 declarations read from them. Sizes scale with the reader's own browser setting instead of staying pinned to px.
  • The fixed tier went from 27 loose values to 11. Six sizes crowded inside 15 to 17 became one: prose, hire copy, the lightbox and the blockquote all read 16. The p strong bump is gone, so emphasis comes from weight rather than a 1.1px size change that looked like a font-loading glitch. Eight sizes inside 10.5 to 14.5 became five steps. The sealed-row label, which spanned 6, 7.5 and 9px across three rules, is one token at 10.
  • Weights 650 and 750 are retired: five declarations in the whole file, used nowhere else in the system. The case section title reads 700 now.
  • The case-study rhythm is one scale: 8 for a sub-head to its own prose, 12 for the body run, 14 for a title to what it heads, 28 for the block break around figures and quotes, 56 between sections. Figures were 26 above and 34 below, which put every image off-centre in its own gap.
  • Removed 15 dead rules. .mosaic-static stopped existing when Highlights2 renamed the wrapper to hl2-static, so those rules had been sizing and positioning an element that is on no page. The company pills read a flat 13px at every width because of it, instead of scaling from 11.5 to 19 as the rule intended. Deleting changed nothing on screen; verified identical at 390, 760 and 1440 across all four tabs.
  • The deck embed is gone from the GitLab Talk study. A visitor was waiting on pitch.com for the page's load event, measured around 80s. The page now loads in under a second.

2026-08-05 · The phone footer is cut to a sign-off

Deploy: anirudhux-9wcekcboe-anirudhux.vercel.app → anirudhux.com

  • Two sitemap columns leave the phone band. Explore repeated the switch pill, which is fixed on screen at all times, and Highlights listed projects the reader had just scrolled past. Testimonials and Tools are dialogs the Hire me surface already holds, and Hire me itself is in the nav, so nothing became unreachable.
  • What remains: the brand stack, Resume, Contact and LinkedIn on one horizontal row, the (c) line and the theme switch. The three blocks now step by an even 30px; the old 22px brand margin was tuned for a two-column sitemap and left a 50px hole above the links. Tablet and desktop keep the full footer.
  • The smoke gate is hermetic now. It had started failing on /community/gitlab-talk: the page has a pitch.com deck iframe and the parent's load event waits on it, measured around 80s in a real browser against a 30s gate. Third-party requests are blocked at the context, so the gate tests our export rather than a vendor's uptime. The static server also answers Range requests properly now.

2026-08-04 · The phone band gets the card grammar

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

  • Rows stack and centre on the phone. The side-by-side plate read dated, so every Work row now leads with its thumbnail on one 132px plate, cover cropped, with the title and the line under it centred beneath. One height for every thumb: the source aspect no longer leaks into the layout, which is what made a short Nutella beside a tall consumer study look ragged.
  • Radii are a system thing: no sharp media edges anywhere on the four homepage addresses, Highlights rows included.
  • Sealed rows skip the band. The phone gets most of the incoming traffic and a locked plate spends that attention on nothing; they still render on tablet and desktop.
  • Phone titles include the company (PhonePe UPI Lite, Ennoventure Design System, and so on), so the group headers retire on this band; the research stack leads with the consumer study. Wider bands keep their headers, names and order.
  • Community takes the same grammar: Transform Design, GitLab Talk and Various Meetups stack and centre; PRSOS and DARD skip the band. The AI tab keeps its left-bleed device crop, deliberately: flat artefacts take a cover crop, device shots do not.
  • Separators and the fused card's closing edge now follow visual order. Hidden and reordered siblings still count in the DOM, so :first-child and :last-child kept matching rows that render second or not at all.

2026-08-04 · Work tab recomposed around the Design System

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

  • Columns re-sorted by family (my call, on desktop-lab): Design System is an Ennoventure thing, so it moved right under the Ennoventure umbrella and the cross-company research stack moved left under PhonePe. The config comment had claimed this arrangement since July; the grid matches it now.
  • Design System is the flagship tile: top-right at full height with its diagram visible at rest (the Work tab shows evidence without a hover, so the AI-tab reveal grammar does not apply here), centered at 360px, corner icon retired. Its blurb absorbed the Ennoventure credential line.
  • Research Reports renamed from Design Research Reports (it names the shelf it links to), title-to-thumbnail gap halved, and the consumer study returns at tablet; every band now shows all three reports.
  • The NDA label retires everywhere, chip and plate stamp both: the lock says it, and the surrounding context now reads sealed-on-purpose.
  • Tablet and phone follow: slug tiles learned tabletLast so the flagship takes the big slot in the zigzag, and the phone row shows the diagram plate.

2026-08-04 · The Design System case study ships

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

  • The NDA comes off: /work/en-design-system is live, reworked section by section with me holding the pen (seven sections, h3 sub-heads for the governance split and the conclusion's Takeaway/Performance/Impact). The standalone tile and the phone row both link in; the NDA-door machinery emptied.
  • Hero motion: my animated governance diagram as the walkthrough banner (2.4x, 11.8s loop, 353KB in-repo, canvas lifted clear of the player controls), poster still cut from frame one.
  • Five exhibits under their sections (typography, palette, spacing, radii via the new h3 figure key, interaction states), captionless by my rule; caption became optional through the figure pipeline.
  • The Tools card returns on a Work page as my named exception: Claude, Claude Code, GitHub. The positioning line seats the under-title lede, consistent with Constella. og-still cut; llms.txt picks the entry up automatically. PARKED entry closed.

2026-08-03 · Design System study drafted, then benched

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

  • The Design System case study got its first full drafting session (my dictation, a deep KB, three cuts, a dev page rendered through the real case system for review) and was then parked on my call: the narration is not my voice yet, and the NDA line is undrawn. Drafts stay whole in for cowork/; the dev wiring is torn down; the tile keeps its NDA; production shows no trace (verified 404).
  • PARKED gains the entry (lib/curation.ts) with the working-set map and the open questions for the revisit.
  • The register skill gains the duality-header ban (my call-out, encoded with the fix pattern).

2026-08-03 · Research link previews actually deliver

Deploy: research-bg4u2rfha (research.anirudhux.com; folio untouched. All fix files are in gitignored private-refs; this entry logs the satellite ship)

  • The PhonePe report never had working previews: its og tags were inside the bundler template JSON that only client JS renders, invisible to every scraper. The transform now injects the meta block into the wrapper head (with an assert), verified with a scraper-agent fetch on all three pages.
  • Cards re-rendered at native 1200×630 (they were 2×, 0.8–1.1MB, over WhatsApp's ~600KB cap; now 280–375KB) and all three pages declare og:image width and height for first-paste rendering.
  • www.research.anirudhux.com attached (my new CNAME plus a production domain on the project; a raw alias went behind Vercel SSO, and domain registration is the fix). Verified the unfurl in WhatsApp.

2026-08-03 · Docs and ground-truth sync; the dump pen

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

  • llms.txt gains the research satellite: the agent site map now names research.anirudhux.com with all three reports (verified live, 3 refs). research.anirudhux.com also serves its own robots.txt now (deploy research-aaoys3aur).
  • Docs synced to today's truth: ARCHITECTURE.md documents the satellite beside the museum wings; FOLIO-KNOWLEDGE-BASE.md gets a dateline note so its July netlify URLs can't mislead; CLAUDE.md lists all five docs and the asset map's private-refs rows.
  • private-refs/dump/ created: the review pen holding everything chuckable (zips, mined study sources, extracted report originals, the ten generated_pages sidecars; 15M). Nothing references it; I empty it at will.
  • Memory updated alongside (the flagship pipeline reflects the shipped reports; the OG-preview-unprompted rule encoded).

2026-08-03 · Filesystem reorg: one home per asset type

Deploy: anirudhux-4mdxytwh1-anirudhux.vercel.app → anirudhux.com

  • public/ consolidated: every glyph and logo is now in public/icons/ (the work_assets / projects_assets / community icon sets merged in); portrait/ and tools/ folded into public/assets/; community_assets renamed community. Reference sweep across bento-config, BentoTiles (path helper), ShowcaseFold, HireMeContent, tools.ts; all moved paths verified 200 in production.
  • Strays deleted: root ak.jpeg (its processed webp is the served avatar), four orphan portrait-anim*.webm, the og-cards review PNGs, every .DS_Store. public/_preview/ is gitignored now.
  • private-refs/ bucketed: sources/ (capture sources, zips, the ten generated_pages sidecars), ops/ (uxr-transform.py, og-cards.mjs), research/ frozen in place; script paths repointed.
  • The asset map joins CLAUDE.md: one home per type, including the walkthrough-in-repo vs Figure-clips-on-Blob distinction.

2026-08-03 · Research chrome goes folio-native; phonepe22 becomes the study's face

Deploy: anirudhux-9imxazbf2-anirudhux.vercel.app → anirudhux.com

  • Research pages use the folio's real chrome now (deploy research-rkmzo2cfr): a fixed frosted 56px bar at the browser top on all four pages, the footer as a full-width band flush with the page bottom, columns centered at desktop. The old in-container header (with its stale tagline) is gone; the transform script lints it dead.
  • All three reports get OG cards in the folio anatomy: PhonePe (phonepe22 inset), Nutella and UCI (Work-tab thumbs as insets, my titles "Nutella counterfeit study" / "UCI counterfeit study" on the cards); og/twitter meta wired on both new pages.
  • phonepe22 sweep on the folio: the consumer-study row thumbnail regenerated from my capture, with scoped left top crop rules in both row bands (desktop and phone); anchor top-left, crop bottom-right.
  • The CLAUDE.md satellite section updated to the new chrome contract.

2026-08-03 · Nutella + UCI reports join the research shelf

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

  • Both Ennoventure-era studies are now native at research.anirudhux.com/nutella and /uci: standardized chrome (wordmark plus Hire me header, four-line brand-stack footer), each in its artifact's own family colour (Nutella amber, UCI navy), responsive to 390, body copy byte-identical to the source artifacts. Built by two parallel agents.
  • The UCI bike diagram fits every desktop width down to 1160 (the whole SVG scales to its section); on phones it pans horizontally at natural size, my shortcut. Fixed the source's own 34px clip at 1440 as a side effect.
  • Shelf cards wired: all three reports now route inside the subdomain with real thumbnails (Nutella and UCI reuse the Work-tab thumbs); netlify links retired from the shelf, the Work tile rows, and content.ts live: fields (llms.txt follows).
  • Research chrome standardization ships with it: report and shelf footers are the folio brand stack; the transform script now lints dead chrome strings; satellite ops documented in CLAUDE.md.

2026-08-03 · Consumer study goes live; case pages join the family worlds

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

  • PhonePe Consumer Study 2022 is published at research.anirudhux.com/phonepe (new research subdomain, its own Vercel project; the shelf at the root with Nutella and UCI placeholder cards). The Work tile's DRR row sheds its NDA seal: href out to the report, real thumbnail from the report's opening view.
  • Case pages ground in their family colour in both themes via data-group joining the homepage's world system; the ghost-white fallback survives only on hire-me.
  • New skill: .claude/skills/writing-like-anirudh, the register as an invocable tool (hard rules, caught failure modes, my line patterns).

2026-08-02 · Contact modernized: dots out, form visible, labels retired

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

  • Dot grids out: the phone top-of-page fields (Highlights T1 plus tab meta zones, ≤600 only; desktop and tablet keep theirs) and the Contact dialogs' dot ground on every platform. Element, spotlight JS, and ~70 lines of CSS deleted at the source.
  • The Contact section joins the section rhythm in the Hire Me surface: 48px cadence and 24px title gap like every sibling (the dialog variant had a padding:0 that pulled the title against the divider).
  • Form fields read as live inputs: white fill (dark: 7% ink lift), 26% ink border, labels retired; the placeholder is the label proxy (my copy verbatim: "Enter your work email" · "Where do you work?" · "Purpose of contact?" · "Give me some context - a line or two about what you have in your mind."). Screen readers keep sr-only labels.

2026-08-02 · Declutter pass: identity line and tile arrows retired

Deploy: anirudhux-6x2ikkg3u-anirudhux.vercel.app → anirudhux.com

  • The lens-bar identity element is killed whole (my call): wave, "Designing & building since 2014", "Previously at" plus logos, pills, the hidden Hire Me click, the arrow. It existed as visual anchoring; ≤820 proved the anchor unnecessary. Switch pill pinned right (flex-end); ~65 lines of dead CSS and the rotation machinery removed.
  • Tile and row ↗ arrows retired sitewide (clutter, plus mid-title wrap at in-between widths): tile heads, bento rows (the href state now renders nothing), Highlights phone rows. Locks, NDA chips and play stubs stay. One deliberate survivor: the case hero's live-product ↗. A proper leaves-the-site language comes later; the row table updated in CLAUDE.md.
  • Team and Tools cards go transparent on case pages: the family wash clashed with the page ground; the hairline draws the card now.
  • Constella: the site's only blockquote folded into the preceding paragraph as a bold close. ExpressBuy: Ashna Jain reads Product Lead.

2026-08-01 · OG card polish: centered link line, smoke gate, ops docs

Deploy: anirudhux-857x3vcfx-anirudhux.vercel.app → anirudhux.com

  • Card bottom row: the URL now centers on the title's midline (it was baseline-hung and read as off in real share sheets; my catch).
  • Smoke gains an OG-card gate: every leaf case route must ship its PNG card, its html must point og:image at it, and its still must exist in public/og-stills/. Negative-tested (a hidden still fails with the exact filename).
  • CLAUDE.md: the full link-preview contract (template anatomy, the one-file step for a new leaf, vercel.json do-not-delete, the UTM pasting convention); the new-case-study checklist gains the og-still step.

2026-08-01 · Per-page link previews: 13 OG cards from one template

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

  • Every leaf case page now shares with its own preview card; the homepage and the four tab pages keep the default face card. 13 cards: 4 Work (forest), 4 AI (moss), 5 Community (copper).
  • One template in code (lib/og-card.tsx, next/og at build time): the project's still uncropped in the body, the name bottom-left in the family colour, the spelled-out URL bottom-right, the site's tile wash as the ground, Manrope throughout. Long names scale down instead of wrapping (my catch).
  • Stills are per-slug PNGs in public/og-stills/ (the OG engine reads png/jpeg, never webp), sourced from each project's existing preview asset. UPI International also got its phone-row thumbnail fixed to show both Pay cards whole (contain, this asset only).
  • vercel.json is new: one header rule forcing image/png on the extensionless card routes; scrapers reject octet-stream.
  • Team avatars: my portrait crops tuned; the disc fill grounds the transparent cutout on both team cards.

2026-08-01 · ExpressBuy dressed: figures, my VNAV, figure-spacing grammar

Deploy: anirudhux-1ihcw0bpe-anirudhux.vercel.app → anirudhux.com

  • ExpressBuy gets its three figures (my exports, native res, bare, pan on phone): the core user journey under "In the PhonePe ecosystem", coupons under "Whose coupon discounts are they, anyway?", the payment leg (updated export, opens on Payment Summary) under "Checkout vs payment UX". Sources in private-refs/expressbuy-source/.
  • VNAV rewritten to my thirteen titles; the address-refill section cut, return-to-merchant folded into Respectful data boundaries as a note, the pilot blurb deleted, the conclusion rewritten Cart-style (and de-grandiosed on review).
  • Sitewide figure-spacing grammar (a usability fix, my observation): the header pulled tight to its figure (8px when adjacent), the caption fenced to its image with a faint hairline beneath, 34px before body prose. One .case-figure rule; every study inherits.
  • Team cards tuned: I lead both rosters as "SPD (Project Lead)" linked to /hire-me; Amit off ExpressBuy (Roopa and Ashna only); UPI International adds Atul Kumar and Animesh Bagora; the avatar disc fill grounds my transparent portrait; face crops recentred; 18px phone row gap.
  • The ExpressBuy hero positioning rewritten question-first.

2026-08-01 · Team cards, ExpressBuy rewrite, tools bars go AI-only

Deploy: anirudhux-1plj3f7jh-anirudhux.vercel.app → anirudhux.com

  • The Team card joins the case-study pipeline: team: in projectPages renders a second plate under the tools bar with avatar, linked name, designation. ExpressBuy (me · Roopa Nadgiri · Ashna Jain) and UPI International (me · Amit Vernekar · Atul Kumar · Animesh Bagora). I lead both as Senior Product Designer (Project Lead); my name links to /hire-me in-tab, the others open LinkedIn in a new tab. Real avatar webps in assets/profiles; sources in private-refs/.
  • Tools bars belong to the AI tab exclusively (my call): Cart and ExpressBuy drop their Figma chips; all four PhonePe studies are consistent now. Rule encoded in CLAUDE.md.
  • The ExpressBuy study rewritten end to end: 15 plain VNAV titles, the theatrical coinages cut, written for a stranger. The hero positioning rewritten to the question-first construction. "The team" prose section retired; the card is the single home for credits.
  • The intro-shape rule enforced: study bodies never open with headerless paragraphs. ExpressBuy and Cart fixed, all 13 studies audited, the rule in CLAUDE.md.
  • Phone polish: team rows breathe (18px gap ≤820); the card stands alone when no tools bar precedes it.

2026-08-01 · Cart study visual pass: figures, retitles, dark-marker fix

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

  • PhonePe Cart gets its figures: 7 figures (10 renders with theme pairs) across 5 sections. The research grid, IA stickies, core flow, the user-flow swimlane (light/dark), the RCBP scope map, the coin item (light/dark), the remove-vs-clear confirmations (light/dark). All render bare; my exports have their own grounds. Sources in private-refs/.
  • All 12 VNAV titles rewritten (my dictation): The invisible cart · The omnipresent cart · The partial payments trap · The cart breaks the funnel, and eight more. Figure keys renamed in lockstep.
  • "Three reasons why this did not ship": collective framing; the braggadocious opener cut.
  • Marker density 6 → 13 across the study, and a sitewide dark fix: the .marker wash was light-tuned (16% family, invisible on near-black); dark now lifts family toward ink at 30%. Every case study's highlights become visible in dark for the first time.

2026-07-31 · Backburner hygiene: stale doc drift, orphan config, branch cleanup

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

  • CLAUDE.md rewritten in two spots: the 'Known open work' bullet reflects post-ExpressBuy, post-Cart reality (Ennteract 2.0, Printer Toolkit, Vyu = NDA; PhonePe Consumer Study = note-only). A new 'Week-to-week additions' section documents the repeat rituals (new case study, copy update, thumb swap, park, cbv) so a cold-start session can execute without archaeology.
  • README.md and docs/ARCHITECTURE.md: origin URL Codeberg → GitHub (matches post-migration reality). CHANGELOG masthead: the cbv definition Codeberg → GitHub (the ritual name stays 'cbv').
  • lib/project-pages.ts: two orphan entries removed (en-platform, en-printer-toolkit). They had no generated_pages/<slug>/ folder, were absent from LIVE_CASE_SLUGS, and were never reachable (both NDA tiles).
  • Local dev: .claude/settings.local.json (gitignored) had four stale codeberg curl probes in the Bash allowlist; pruned.
  • Branches: merged local and remote branches deleted (case-study-lab, desktop-lab). video-lab kept (parked per lib/curation.ts).

2026-07-31 · Repo hygiene: file aggregation, dead-file removal, disk cleanup

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

  • public/ organized by kind. Loose files at public/ and public/assets/ moved into semantic subfolders: public/portrait/ (6 files: 2 stills plus 4 anims), public/tools/ (capso, cleanshot, rotato), public/assets/profiles/ (5 team headshots), public/assets/ work_assets/ (adori, ennoventure, phonepe brand pngs), public/icons/ (arrow-right-bold svg). All <img src> refs updated in HireMeContent, HireTestimonials, ShowcaseFold, lib/tools.ts.
  • Root de-cluttered. FOLIO-KNOWLEDGE-BASE.md moved to docs/; folio-tree.html and readiness-board.html (Jul 9 dead scaffolds, no code references) deleted.
  • Local disk trim (dev-only, no ship impact): .next/ and .vercel/output/ nuked (they regenerate on the next build and deploy), git gc --aggressive ran. Folder size 980 MB → 241 MB.

2026-07-30 · Phone card grout; Community photo crops

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

  • The phone card separator between rows now uses the nested-lift formula (family mixed with ink first, then transparent), theme-adaptive: 8% in light, 22% in dark. Visible on both grounds; it matches the same family the outer tile stroke uses at a lower prominence.
  • Community photos recropped to 16:9 (transformdesign 1600×900, various-meetups 1200×675; trimmed from the top where the ceiling lights were). Both now fill the tile-reveal container edge to edge, same as the GitLab illustration; no more letterboxed padding on 4:3 sources.

2026-07-30 · Migration to GitHub; fused-shelf grout redraw; UCI thumb

Deploy: anirudhux-5tvu01bab-anirudhux.vercel.app → anirudhux.com

  • The repo migrated Codeberg → GitHub (private, github.com/anirudhux/folio). Full history rewritten with git filter-repo to swap the commit author email to the GitHub noreply, so the contribution graph attributes retroactively across all 322 commits. Backup bundle in ~/Downloads.
  • The cbv ritual name stays despite the C standing for Codeberg; the mechanics are unchanged. CLAUDE.md remote URL, pinned identity, and the cbv definition updated to GitHub.
  • The footer's Built-with tooltip and the Hire Me colophon: Codeberg → GitHub. Case-study "Tools used" listings keep Codeberg (accurate to when those projects shipped; my explicit call).
  • Fused-shelf grout redrawn: the slab top hairline gone; per-card inset pseudo-element dividers replace border-based grout. Every divider insets 24px from its own card's edges; no line touches another. PhonePe's 2×2 now has a deliberate 48×48 void at the crossings; the visible plus is out.
  • The UCI thumbnail replaced with a carbon-frame anatomy illustration (960×576, the source stays in private-refs/).
  • Bench cleanup on 2026-07-30 (dev-only, no deploy): four stale entries cut; the research-pipeline-as-AI-project park entry added.

2026-07-29 · Work tab: card copy pass

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

  • Notes forked by surface on the six Ennoventure and DRR rows where the constraints genuinely differ: the canonical note holds the longer desktop-hover copy (my originals), phoneNote the compressed phone-card version. The four PhonePe rows stay single-string; a reader already knows what UPI Lite, International, Cart and ExpressBuy are.
  • Phone titles disambiguate the way the desktop umbrella tile does: seven verbose phoneTitles (Ennteract 2.0: Brand Protection Platform · Package Printer's Asset Management System · Vyu: Consumer Web + Native Apps · The Agentic First Design System · Nutella 400g: Counterfeit Study · UCI: Cycle Equipment Certification · PhonePe: Consumer Usage Study 2022). Desktop titles unchanged.
  • The UPI International note breaks after the colon on hover (white-space: pre-line).
  • Card body flex: the 60% cap becomes auto; the media plate 40% → 34% so UCI's phone title fits two lines instead of three.
  • Design Research Reports gets 'Consumer Study' as its third section; the PhonePe Consumer Study card wires up its first note.

2026-07-29 · Work tab: the fused shelf ships

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

  • Desktop Work tiles rebuilt as fused slabs (≥821): rows became card sections flush inside each tile with a transparent ground, grout plus a top hairline, no inner boxes. PhonePe runs a 2×2 (UPI Lite · International on top, Cart · ExpressBuy below); Ennoventure and the research tile run equal thirds. A day of iterations (piano keys, Kit Kat, zigzag) distilled to the simplest form.
  • Hover swap replaces text-on-card: the strip and title exit, a two-line factual note centers in the cell; 0.22s intent delay entering, instant exit. The community tile's reveal mechanism, at card scale.
  • Dark pass: slab strokes 22 → 45%, hover wash 24%, NDA plate frames 26%; the light-tuned mixes were invisible on near-black.
  • "Product & Design Research" renamed "Design Research Reports"; the consumer study returned as its third card. PhonePe's sub drops the 400M+ repeat (T1 owns the stat). Printer Toolkit's image retired: an image means openable, everywhere, no exceptions left.
  • The desktop-lab branch retained for future passes.

2026-07-29 · ExpressBuy case study ships, out of NDA

Deploy: anirudhux-995vzfp1l-anirudhux.vercel.app → anirudhux.com

  • ExpressBuy is live (/work/expressbuy): PhonePe's checkout for storefronts it does not own; a 0→1 MVP told in 14 sections. The spine: the three-rung device ladder, instrument vs mode (the Payment Summary split, my call), the ownership data boundary, and the address flywheel. It ends on the honest de-prioritized verdict: the pilot ran, the numbers stayed opaque, "I don't know" said plainly.
  • The bento row came out of NDA (lock plus chip → href ↗); the dummy-merchant CUJ strip stays as its face on the row and the Read-more rail.
  • A teammates callout closes the lede: Amit Vernekar, Roopa Nadgiri, Ashna Jain, linked to LinkedIn.
  • The knowledge base (generated_pages/expressbuy/) built from the full flow-by-flow walkthrough; figures deferred to their own sprint.

2026-07-28 · PhonePe Cart case study ships; Work tab recomposed

Deploy: anirudhux-12kxe6jmd-anirudhux.vercel.app → anirudhux.com

  • PhonePe Cart is live (/work/phonepe-cart): the self-initiated bulk-payment concept, 12 sections ending in the argued no (behaviour, conversion, licensing). It replaced the B2B Payment Gateway NDA row; a clickable story beats a locked title. The row and the Read-more rail show the Cart Components sheet (960w webp).
  • Work tab recomposed (merged from case-study-lab): PhonePe leads the left column at the tall ⅘ share with Design System under it; Ennoventure right at ⅗ with Product & Design Research under it. The tablet zigzag is intact (TABLET_BIG is slug-keyed; tabletLast moves to Ennoventure).
  • Quick wins: the PhonePe consumer study row removed on all devices (not available right now); section dividers dropped from the PhonePe and P&DR tiles; the Design System NDA chip trails to the card edge on desktop, the same rule as rows.
  • P&DR gets its sub back: "Intelligence briefs from a five-agent pipeline: every claim checked at its source." It names the system behind the two reports.
  • Reference material (agent definitions, the pipeline flowchart, the Cart Components source PNG) moved out of public/ into gitignored private-refs/; verified 404 on production.

2026-07-28 · llms.txt goes hiring-first; docs cleanup

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

  • llms.txt leads with hiring (my call): availability plus a "Best fit for" section (the four target roles: Founding Designer, Principal/Staff, Head of Design, AI-Native Design Lead) directly under the title, before Summary, Roles, and the projects. A recruiter or screening LLM hits the hiring signal first. Gated on OPEN_TO_ROLES, so the lead drops if availability flips off.
  • One source, no drift. The availability line and Best-fit roles moved to lib/content.ts (hiring), read by both /hire-me and llms.txt. This also fixed the drift where /hire-me's meta said "Product designer, 11 years" against the site's Design Lead / 12+ years.
  • Corrected llms.txt's stale "human/agent switcher" line (no such toggle ships) to point at the human site.
  • Docs cleanup: CLAUDE.md trimmed (195 → ~120 lines, every invariant kept), the README rewritten to the four-tab architecture, FOLIO-KNOWLEDGE-BASE's "multiple versions generated" premise corrected, stale HANDOFF.md and dummydata.md removed.

2026-07-28 · Revert inlineCss; the LCP chase moves to field data

Deploy: anirudhux-lbbhijqi1-anirudhux.vercel.app → anirudhux.com Reverts the inlineCss entry below. It could never be shown to help, and it had real downsides, so prod goes back to the clean render-blocking <link>.

  • Why revert: the "81 vs 62" that justified inlineCss was a bad comparison (warm prod against cold preview infra). Held constant, inlineCss showed no LCP win, it tanked the text-to-code ratio (149KB CSS in the HTML), and the client re-fetched the CSS after hydration anyway.
  • The real finding: synthetic mobile LCP for this one page measured 3.2 / 5.1 / 4.7 / 9.0 / 7.5 / 7.6s across tools and environments. The lab number is noise-dominated; chasing it further is chasing noise.
  • What stands: the LCP element (the Constella row image) is already optimal (priority-hinted, discoverable, eager, ~48ms load); PostHog is trimmed (~94KB JS off); the wave is 60KB.
  • The decision: stop tuning against synthetic LCP. PostHog web-vitals is live, so real-user field LCP accumulates over the coming days, and that is the number Google ranks on. Revisit LCP from field data.

2026-07-28 · Render-blocking CSS: inline it (the mobile lever)

Deploy: anirudhux-c14qgm4fy-anirudhux.vercel.app → anirudhux.com The third approved lever, and the one that matters for mobile: the global CSS shipped as a render-blocking <link>, so first paint waited on that request (~610ms, amplified by mobile's slow-4G throttle; this is why desktop scored 97 and mobile lagged).

  • experimental.inlineCss: true (Next 15.2+, framework-aware). The whole sheet now inlines into a <style> in <head>; zero render-blocking stylesheet links in the served HTML. Verified live and in both themes.
  • Flash-free by construction. The entire sheet inlines, both themes' rules included, so a dark-mode visitor has every rule at first paint. This is why I skipped a critical-CSS extractor (critters/beasties): those analyse a themeless exported DOM and defer the dark rules, flashing light to dark. That path was tried (optimizeCss) and is a no-op for static export anyway.
  • Known trade-off: Next's client runtime still re-fetches the CSS files after hydration (for client navigation), so the CSS bytes ride first load twice. That fetch is post-paint and non-blocking, so it does not gate FCP or LCP; the render-blocking penalty is what got removed.

2026-07-28 · PageSpeed levers: lighter analytics, lighter wave, LCP priority

Deploy: anirudhux-33ci2zhgi-anirudhux.vercel.app → anirudhux.com Driven by a Sitechecker/PSI report (mobile LCP 3.2s). Two of three approved levers shipped; the render-blocking CSS lever was deferred (last bullet).

  • PostHog trimmed to core analytics. The defaults preset silently loaded session replay (posthog-recorder.js, ~54 KB), surveys (~33 KB), dead-clicks and heatmaps as separate scripts; none were in use. All four disabled, so only array.js plus web-vitals load now. About 94 KB of third-party JavaScript off the page, and less main-thread work (helps TBT and Speed Index).
  • The waving hand (512.webp) re-encoded. 23 frames down to 12 at the same 1.4s timing: 121 KB down to 60 KB. Transparency and the wave motion intact; frame count was the lever, quality alone barely moved it.
  • The mobile LCP image now loads first. The lead Highlights row (the Constella still) ships fetchPriority="high" plus loading="eager", so the scanner pulls it ahead of default-priority resources. This answers the report's "LCP request discovery" failure. It cannot fix LCP alone while the render-blocking CSS still gates the render.
  • Three oversized "previously at" logos resized (447–554px stored, shown at ~32px) down to 128px. Small, clean win.
  • Deferred: render-blocking CSS (610ms). Next's optimizeCss is a no-op for a static export (verified, reverted). The workable path is a postbuild critical-CSS step, but it risks a dark-mode first-paint flash on this theme-heavy site, so it needs its own careful pass.

2026-07-27 · Static hero (Constella graph), zoomed; feed keeps motion

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

  • The Highlights hero is a still now; every other feed card keeps its autoplay video (the gitlab loop, shape, upi). A large autoplay video cannot hold a stable LCP because its late frame-paint keeps becoming the LCP, so the lead card is a server-rendered image (the desktop LCP, painted at FCP). HERO_STILL (curation) is the one place to swap it.
  • The chosen image: Constella's own product views, sunburst in light, graph in dark, zoomed (scale 1.45) so only the graph is in frame and the app chrome (Reset / Share & embed / the Graph·Sunburst·Tree toolbar) is cropped off. The mesh dropped and the scrim pulled back on the lead so a dark still reads.
  • The still is an <img>, swapped by data-theme. It has to be a real image element to be the LCP candidate; a CSS background-image renders identically but ranks out of LCP contention, so the metric fell to a smaller, later feed card (a detour tried and reverted the same day). Both themes ship; CSS shows the one matching the site toggle (a <picture> keys off prefers-color-scheme and desyncs from the footer switch). Hidden ≤600 so the phone keeps its device-mockup row thumbnail.
  • Also: below-fold feed videos lazy-load (200px), and only the visible theme's capture loads up front.

2026-07-27 · Feed video: first-frame posters, one capture, idle-defer

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

  • Every walkthrough now ships a first-frame poster (base light included, walkthrough-poster.webp, extracted per project); the card paints its still instantly instead of staying blank until the video decodes.
  • Only the visible theme's capture loads up front. The paired path used to preload both light and dark; in light mode the dark walkthrough (~900 KiB) downloaded and decoded while invisible. The hidden one now warms after idle, so a theme flip stays instant.
  • The <source> waits for load plus browser idle; the poster covers the visual through the critical window, so the video download and decode are off the first-paint path.
  • Honest note: these trim real payload but did not lift the desktop score (73 → still ~73–76). Root cause diagnosed: desktop LCP is the client-mounted hero (~2.7s) plus the loader on /, and desktop is graded on a stricter Lighthouse curve than mobile (which holds 93 on the same metrics). The remaining lever is a server-rendered hero poster; parked, my call.

2026-07-27 · Lazy-load the feed walkthroughs (desktop Speed Index)

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

  • The Highlights feed used to preload="auto" every card's walkthrough MP4 (both theme captures each) at first paint: ~8.6 MB up front, the desktop Speed-Index drag. Each card now mounts its <source> only when within 200px of the viewport (IntersectionObserver on the card). The hero and first visible row stay eager (LCP untouched); the below-fold cards defer and load as they scroll near, roughly halving the initial video payload.
  • The observer runs in a post-paint effect rather than the ref callback; a ref callback fires during render before the mosaic lays out, so every card read as top-of-page and the gate loaded everything. Mobile is unaffected (the feed videos already return null ≤600).

2026-07-27 · Per-tab colour worlds: each view grounds in its family hue

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

  • Each homepage tab now grounds in its own family colour, replacing the single global tint (which rang against the green content). The page --bg keys off the [data-tab] already in the DOM: 4% family on white in light, 12% family on pure black in dark (srgb, muted; oklch-on-near-black made it pop). Petrol / moss / forest / copper for Highlights / AI / Work / Community. Case pages and hire-me keep the neutral base (#F8F8FF).
  • The bare lock thumbnails take 24% of their family (on white light, on black dark) instead of the old warm grey; the empty plates read as intentional family tiles, and that finally kills the temperature clash at the source. Imaged plates keep their neutral letterbox.
  • The homepage hue cycle is retired. --hero-accent pins to the current tab's family hue (dark uses a lifted family so it reads on near-black), so the navbar, fold wash, blurb and dot fields all commit to one colour that matches the ground instead of drifting petrol→forest→copper.

2026-07-27 · Page ground warmed to #F7F9FF

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

  • The light --bg moves #F8F8FF → #F7F9FF (a touch lighter and warmer). The 54 color-mix consumers retint from the token; the loader ground and the two opaque phone NDA-chip mixes track it too. Dark unchanged.

2026-07-27 · Sealed-work plates: full-bleed stills, one composite NDA chip

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

  • The seal is one component everywhere now. A composite chip (lock inside the NDA pill, single element) goes beside the title on desktop and tablet (absolute to the row edge, uniform 7px/6px), and as a 2px-inset corner stamp on the phone plate. The Design System tile uses the same chip; the old two-part lock-plus-tag pair is gone. Radii matched at 2px across plates and chips on all bands.
  • Sealed rows can hold their own still. Printer Toolkit (the all-states board) and ExpressBuy (the checkout CUJ strip) now fill their plates edge to edge; my assets, as-is. The remaining sealed rows show a centered lock on a bare plate (interim, until each still arrives) so an empty plate never reads as broken.
  • The phone plate chip is an opaque family tint (transparent went muddy over a still); desktop's title chip keeps its transparent base on the light card.
  • Phone plates locked to true 4:3; the PhonePe consumer study skips the tablet band (the ⅓-width tile could not seat title plus chip).

2026-07-27 · The NDA door; row plates on every band

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

  • Sealed work is askable now. The six NDA rows and the Design System tile open the Contact dialog with a new purpose preselected, "Requesting access to work under NDA". One listener reuses the footer's existing dialog, so no second form mounts. A hover label was built and cut the same day: the click is the affordance, the label was noise.
  • Every list row gets a plate, the phone's card language at row scale: a real still where one exists, otherwise the family lock with NDA set beneath it. Desktop 52px, tablet 38px (rows are title-only there, so a desktop plate towered over one line); phone keeps its 40% card. Lock and chip left the title line entirely.
  • Nutella and UCI show real captures of their live reports, clipped to the content box rather than the page: the Nutella cover block with its stat strip, the UCI annotated bicycle. 21 KiB and 33 KiB. No placeholder plates remain on Work.
  • The card form is gated on having a plate rather than a description, which pulled the note-less PhonePe consumer study row into line with its neighbours.
  • Shipped on the evidence: mobile is 59% of visitors, so the phone Work screen is the primary surface.

2026-07-26 · Pill clearance unified at 84px; B2B PG on phone; swap-time scroll pin

Deploy: anirudhux-2fr5r6pzy-anirudhux.vercel.app → anirudhux.com

  • The pill-over-card overlap (my catch): the mobile system's rule is 84px of bottom padding under the last card (pill 46 + gap 16 + air), but two later rewrites re-derived their own constants: 40px in the lens grid plus Highlights feed (2026-07-11), 64px in the tablet block (2026-07-18). Latent until the Work tab grew tall enough to scroll; at scroll end the pill overlapped the card by 22px. All three read the same 84px now.
  • B2B PG (phone only): new optional phoneTitle/phoneNote on ListRow, CSS-swapped at ≤600. The B2B row reads "B2B PG · Payment gateway rails for online businesses." on phone; full strings everywhere else.
  • Tab switch scroll pin: a second scrollTo(0,0) fires when the incoming view mounts (≤820); iOS momentum scrolling could stomp the tap-time reset and land the new tab mid-document.

2026-07-26 · Row thumbnails at row size: the mobile LCP pass

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

  • Loader v2's earlier reveal exposed the next bottleneck: the phone rows render ~240 CSS px wide but downloaded the full case stills (~1.2 MB across the Highlights feed; ftux.webp alone 331 KiB at 2720px). Mobile LCP rose to ~5.5s and the score dipped to 76.
  • New TILE_PREVIEW_ROW map plus -row.webp variants (720w, sharp q80, alpha preserved, ~240 KB total): the Highlights phone rows and the Work card rows prefer them; hover reveals, the Read-more rail, and case figures keep the full files. Same images, same framing, three times the slot density.
  • Lighthouse on production after: 89 mobile / 85 desktop (from 63/63 at the start of the day); mobile LCP 3.4s, desktop 1.4s.

2026-07-26 · Loader v2: quiet veil, family dot shimmer, 1.55s

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

  • The cold open sheds the orange mesh and grain: a plain ghost white or near-black ground, the wordmark centered and following the live hero cycle (one clock, inherited; never a local instance).
  • The corner counter is gone. In its place a 4×4 dot field under the wordmark (the CodePen DKzBmR recipe): each dot pulses opacity on its own offset duration; each row holds one fixed family colour in pill order: petrol, moss, forest, copper. Deliberately disconnected from the cycle; colour is identity, the same law as the T1 dot fields. Dark lifts the rows in oklch.
  • Duration 2.6s → 1.55s; the count still runs underneath and drives the exit.
  • #loader on the homepage is the bench replay flag: it forces the cold open on every refresh for iteration. Normal skip rules untouched.
  • The bench branch loader-bench holds the lineage; merged fast-forward.

2026-07-26 · PageSpeed pass: lean icon, lean wave, one themed download

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

  • Baseline measured first (local Lighthouse on production): 63 mobile / 63 desktop; mobile LCP 11.9 s. After this deploy: 87 mobile / 71 desktop, mobile LCP 3.9 s.
  • app/icon.png 573 KiB → 60 KiB (the 900px source resized to 512, palette PNG). public/512.webp 280 KiB → 121 KiB (the footer wave: a 512px 46-frame animated webp downscaled to 144px, 23 frames; it renders at 44–72px).
  • New components/ThemeShot.tsx behind all three thumbnail renderers (Highlights phone rows, tile hover reveals, Work card rows): the old useIsDark remount put the light src in the server HTML, so every dark-system visitor downloaded both theme variants. Pre-mount it is a <picture> with a prefers-color-scheme source; post-mount it collapses to the data-theme'd img (a cache hit unless the visitor manually overrides the system theme).
  • The duplicate-thumbnail smoke gate (built after the Work-rows RCA) ships in this commit; the suite stayed green through it.

2026-07-26 · Work rows: own faces, family locks, no false play

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

  • The repeated-thumbnail bug (my catch, with an RCA on the record): the phone Work rows had four borrowed placeholder faces (Constella, Contraire, Anatomy, Shape) across eight rows since 07-18. Every image appeared twice on one screen and none was its own project. UPI Lite and UPI International now show their case-study stills as-is (ftux, forex-anxiety; a single-panel-crop detour was built and killed the same day: it broke the row hierarchy).
  • NDA rows render a family-coloured lock in the media slot on the same plate the thumbnails use: the footprint stays uniform, the state reads at a glance, no borrowed faces. Research title-only rows stay plain.
  • The play disc on thumbnails is dead: it promised an inline player, but rows navigate to the case study where the video is. The title's ↗ returns on card rows as the navigation cue.
  • CLAUDE.md now maps the two independent thumbnail sources (TILE_PREVIEW plus bento-config item.preview): any thumbnail ask sweeps both, at every band.
  • Also in this commit: the repo-privacy doc correction and the backup-bundle script (owner tooling, unused until called).

2026-07-25 · Colour hover, a softer ground, and the footer goes bare

Deploy: anirudhux-ko9uo3z5q-anirudhux.vercel.app → anirudhux.com (One entry, two deploys: the hover interaction went out mid-session as anirudhux-krlvujclw and its cbv was interrupted before the ledger; this entry covers both.)

  • Feed cards respond in colour; position stays fixed. Cursor on a card saturates the footage (1.25) and deepens the petrol veil (0.22 → 0.42 light; dark re-pins its own 0.82 → 0.86 multiply). The −3px hover lift is dead at my call ("not the right interaction pattern for this"). Gated to @media (hover: hover) so touch never sticks a state.
  • The footer dot ground is gone (my call: "not adding any value"; plain is the accepted trade). The footer is transparent on the page's own ground; the wash died 2026-07-24, the dots died today. The CSS records both so neither ambience layer gets re-invented.
  • The page ground softened: light-mode --bg is #F8F8FF (ghost white, cool tinge, on the "never warm tan" law) instead of #ffffff. One token; 54 colour-mix consumers retint with it. Deliberate whites stay: card plates, logo chips, frost mixes, the resume-print sheet. Seam-scanned at 1440, 1014 and 390 across the homepage, a case page, and the Hire me dialog: zero stray pure-white surfaces. Dark is untouched.

2026-07-25 · The card treatment speaks petrol; llms.txt drops its ghosts

Deploy: anirudhux-2792knzpx-anirudhux.vercel.app → anirudhux.com

  • The light-mode Highlights card treatment, rebuilt in one language over an afternoon of my eye. Four moves, each from a screenshot I brought: the mesh dropped from 0.6 to a lighter cast; the charcoal scrim re-cut to hug the text zone; then the deeper question ("why is there no petrol blue treatment to this overlay?") turned both layers petrol. The scrim is petrol glass (0.94 at the foot, transparent at 78%, raised at my call when band titles lost their bed), and the mesh blends normal at 0.22 in light, since multiply manufactured brown murk over any grey frame (Constella dimming behind its own modals). The 1998 text-shadow (hard edge plus heavy glow) became one soft petrol halo. Dark mode is untouched throughout: multiply at 0.82 over near-black is the look there.
  • llms.txt stops listing ghosts: the five content-less placeholder projects (Ennteract 2.0, Design System, Printer Toolkit, Adori interactive, B2B ExpressBuy) emitted bare "Positioning." lines; generation now skips a project with no positioning, no live URL, no proof. They rejoin when they earn content. CLAUDE.md gains the cbv fact-sync line for llms.txt.
  • The resume-print dev surface points at draft-v3 (the ATS pass; owner-private file, never ships).

2026-07-24 · Footer pass: aligned, transparent, a dot ground

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

  • Alignment: the brand lines (anirudhux / Crafted / Shipped) now line up with the blurb text above, at both widths. Phone: the footer rail matches the header's stage-plus-tile inset (34px). Desktop: only the brand column insets by the meta-tile's 48px content gutter, so it aligns under the blurb while the three lists stay on the bento grid.
  • The petrol wash is gone: the footer background is transparent in both themes, so the page's own light or dark ground shows through. It was reading wrong and causing styling issues.
  • New dot ground: a dot field behind the footer, coloured by the active root (petrol / moss / forest / copper via --footer-accent) and masked bottom to top so the dots gather at the foot and fade up into the body. No wave.
  • Mobile fix: the "Shipped with AI in the loop" line was hidden by two legacy rules that dropped the whole note wrapper. Now only the hover tooltip is dropped on touch; the line shows under "Crafted in Bangalore", with more air before the columns.
  • Sentence case: the column headers (Highlights / Explore / Connect) are Manrope sentence case now instead of the tracked all-caps eyebrow.

2026-07-24 · Images zoom now, on click

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

  • Case-study figures were plain static images, and the gallery lightbox had no zoom, so a visitor could only read dense screenshots by zooming the whole page. Any content image now opens a zoomable lightbox.
  • New Lightbox (shared): wheel and double-click zoom toward the cursor on desktop, pinch and double-tap on touch, drag-to-pan when zoomed, a −/⤢/+ cluster, close on ✕ / backdrop / Esc. Hand-rolled on pointer events, no library. touch-action: none keeps the gesture on the image rather than the page.
  • New CaseFigureImage: inline case figures are click-to-zoom, single image per my rule (each stands with its caption). The hidden theme and viewport variants are display:none, so a click can only land on the on-screen variant and opens exactly that one. GalleryLightbox now routes through the same Lightbox, so gallery photos gain zoom and keep their prev/next.
  • A robustness fix found in testing: setPointerCapture ran before the pointer was recorded, and it can throw on an inactive pointer id in real browsers too; a throw would have silently killed pinch and pan. Tracking happens first now, with the capture call guarded.

2026-07-24 · Mobile tab switches: the crawl becomes a snap

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

  • The ≤820 tab transition was fade, dead hang, blank, then a 1.25s crawl, where desktop is one continuous View Transition morph. Three fixes, mobile only:
  • The dead hang. Platform is read up front so the exit hold matches the exit animation: EXIT_MS_MOBILE = 180ms (the p-page-out fade) instead of the shared 320ms, which had held ~140ms of faded-out dead time. Desktop keeps 320.
  • The blank frame. ≤820 now swaps straight from exit to cards in one synchronous step, never through the empty morph stage; the incoming view mounts already rising over the faded ground. Morph is desktop-VT-only now.
  • The sluggish rise. p-page-rise 1.25s → 0.55s (phone), t-page-rise 0.95s → 0.6s (tablet). Mobile now reads as fade (180ms) then rise (550ms), continuous.
  • Desktop's View Transition morph is byte-for-byte unchanged (gated on !document.hidden && !mobile). Verified on dev: the swap happens at ~180ms with no blank frame, the rise releases its transform to none, the dot ground stays viewport-fixed, and a rapid three-tab burst settles cleanly on the last.

2026-07-23 · Analytics: the six named conversion events

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

  • Wired the conversion funnel into PostHog on top of the autocapture defaults: contact_form_submitted (the lead, with the purpose select), the diagnostic contact_form_started, hire_dialog_opened and contact_dialog_opened (with section and trigger), resume_viewed (with the surface it came from), and lens_switched (tab plus origin).
  • One helper, lib/analytics.ts: a typed track() over window.posthog.capture with an SSR guard. The snippet queues calls before array.js loads, so early fires are never lost.
  • Verified on dev that all six fire with the right properties, and that contact_form_started fires once only. contact_form_submitted was left untriggered in testing on purpose, since a real submit sends a live email; it uses the same success branch that flips the form to its sent state.

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 ships 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

  • The route prune (my 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 stays 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 scrolling beside gallery, embed and Read more. It now goes in a .case-toc-col stretched to row 1 only.
  • Design System tile: lock and NDA aligned on the row mechanism. The pair was dropped inline into the h2 with no flex context and rendered at two heights. .tile-nda-pair gives it the rows' flex centring, the 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

  • A site-wide text audit (my 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 and proof line in content.ts, the UPI figure captions, card ledes, the hire timeline plus its pill-tooltip twin, best-fit cards, NDA tooltips, and llms.txt. My register throughout: semicolons, colons, full stops; en-dash year ranges. The stale "Narrated: play with sound" caption died with the mute.
  • The law is structural now: CLAUDE.md holds the register law, and smoke fails any build with an em-dash or ", not " pivot in rendered copy. Exemptions are allowlisted by my 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 (my words: "which sane person would maintain different types of footers?"). Every page (case studies, placeholders, /changelog, the homepage) closes on the sectional footer: brand stack plus signature lines, Highlights/Explore/Connect, © plus the 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 (the homepage renders pixel-identical). The wash takes the host's family colour: copper, moss or forest per case family via the new accent prop, the tab colour on the homepage, petrol elsewhere.
  • Constella's light walkthroughs trimmed (my 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 and 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 (my catch: Constella stuttered for seconds on a mode flip, then popped). The old key={src} remount refetched and 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 plus CaseFigureVideo). A playback-sync effect pauses the hidden one (display:none fails to stop playback), and the pair rules use 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 (my 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 plus www attached to the project (Namecheap A @ → 76.76.21.21, www CNAME → cname.vercel-dns.com; my 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 use 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 and 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 my cut, exported to PDF, hosted on Drive (deliberately off-Vercel), and present 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 (my 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 and year sweep: title tag, OG, description and 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/ (the repo is public and public/ ships; neither may ever hold them). The draft commit was dropped before it reached the remote. Verified on prod: /resume/draft-v1.md → 404. This 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 holds the two marquee credentials, Transform Design (founded) over GitLab Talk, and the small column stacks Various Meetups / PR;SOS / DARD at 40:30:30 (it settles at 39:31:31 on content minimums). Founder beats attendee, talk beats circuit. The 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. The 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 (my 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 states 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, so reorders were blind; now they see.
  • I re-curated the feed via the bench: 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); the lede is 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 follows the meetups recipe: positioning, "The movement" (the org's own tagline; the 2019–2020/COVID ending goes in the body, since 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 and ambiance, latest conference first, TDConf3-Mix packed-room hero), and 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 (a missing tiles.ts entry had it falling to the forest-green default). Curated into Highlights via the bench; its feed card uses the hero still (the walkthrough-404 trap, caught by smoke).
  • Class-level fixes found on the way: .case-prose a did not exist, so every case-page link rendered as plain ink; now family-coloured and 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 refuse to 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 arrives. Verified on prod: 4 videos plus 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 my own checkpoints.

2026-07-22 · Work tab: NDA chips across the gated stack; notes align

Deploy: anirudhux-afz0skbch-anirudhux.vercel.app

  • Lock plus NDA on the whole gated stack: Ennteract 2.0 · Printer Toolkit · Vyu · Design System (tile and phone card) · PhonePe consumer study join B2B Gateway and ExpressBuy; play stubs gone (no implied walkthroughs). The nda contract re-written to my definition: the reader can't access this because of an NDA, and 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 rendered 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 are identical now.
  • The 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 (mine): 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, the dialog global in layout, lazy-loaded on first open. Deleted: the iframe modal, its Escape relay, HireDialogClose, the standalone page composition.
  • The address contract: an in-site open writes /hire-me, close restores the origin path; a shared /hire-me link renders the homepage with the dialog auto-open (the mount race solved with a pending-open queue), and close goes to /. /hire-me joined HOME_PATHS (the load-bearing template exemption).
  • Inside the dialog: CaseToc survived with a scrollRootSelector (the panel is the scroller; it is the layout as much as the nav, and removing it let prose sprawl past its 720px measure). The colophon became "Tools I work with" (the full roster; the built-with subset stays 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 and 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, the Contact dialog's exact header technique, no eyebrow variants), and the slim footer's Built-with tooltip. Rotato and Supabase joined; Clideo cut (no mark). All marks normalised to 18px across svg, raster and emoji, class-level.
  • The brand column restructured: portrait and bio line out (the T1 one viewport up already introduces); a wordmark plus signature stack instead: ❤️ Crafted in Bangalore · 🤖 Shipped with AI in the loop (the Built-with tooltip attaches to it, left-anchored; centered it clipped at the rail). © goes 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 takes 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.

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 to footer is 36px now.
  • The dot ground is unwalled (my 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 plus 28px footer pad), so the bottom-weighted mask paints dots down to the footer hairline. The gap measured 0 on prod. Highlights' T1 excluded (its sticky column already owns its ground); tablet and 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 and 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), a uniform quick sink on exit. The 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 the 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 arrive (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 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, the 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, the 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 in the animation-lab merge: the sectional footer (portrait plus 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; the loader stays a front-door-only ritual. Smoke: 15 routes crawled, no dead links, overflow or 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 fell 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 my 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 plus ~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 instead of a light-mode-only fix. Manual "1. / 2. / 3." prefixes dropped; the styling holds 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, so 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.
  • The 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 stands 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). A 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 (my 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. The specificity trap: the dark plate is a separate [data-theme="dark"] .case-figure img rule at (0,2,1); the override must come 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, so no amount of CSS gets from one to the other.
  • The .case-more-cta label is "Read More"; a 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 in (.claude/settings.json plus .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 plus 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 genuinely one file for both themes now. I 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 has no background in dark, so the page ground reads straight through. A 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 no alpha test; scan the whole buffer.
  • .case-more-cta became an inline-flex unit. The arrow kept 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 is between the text node and the glyph. display: inline-flex plus gap: 4px removes the opportunity entirely, so a future longer label can't reintroduce it. Label shortened to "Read More" (my call). Verified single-rect at 1440 and 700.
  • The 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 and 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 have an AAC track (the narrated "audio trial"), so the audio was preserved at 128k instead of stripped, and CaseFigureVideo's controls (never autoplay, never muted) does real work. The 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 separate from locked. "Not written yet" is a promise that eventually arrives; 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 plus 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: 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: the 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 avoid opening identically). The Transaction History asset is one file for both themes at my 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 holds 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 and 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 rather than whatever tab React happened to hold. (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.
  • The smoke gate tightened: the three tab routes must 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, unfixed: the Tab union still holds 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 plus generated_pages/, positioning filled in content.ts, the slug added to LIVE_CASE_SLUGS. A hand-rolled standalone route was built first and deleted: it silently dropped PageAmbience (family arc plus 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 and report links keep target=_blank).
  • Section video. Figure gained video: one url, or the light/dark × desktop/phone set. A new client component CaseFigureVideo picks the variant by theme plus viewport (CardVideo's pattern: mount gate for hydration, key={src} for a clean remount). This lets a walkthrough go 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 are 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 go in public/.
  • All site videos drop their download affordances: controlsList="nodownload noplaybackrate", disablePictureInPicture, right-click suppressed. Friction rather than 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 hold alpha), and 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. The null-detector case page dropped 14MB → 0.8MB.
  • Walkthrough mp4s re-encoded at CRF 28 (they 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; the loop.gif poster → a static webp frame).
  • Dead code removed: BackLink, CopyEmail, Glyphs, UseTransform, ZoomStage, DotField (plus the motion dep, 4 pkgs pruned). Runtime deps 6 → 5.
  • Perf: the ShowcaseFold feed pipeline memoized (it was rebuilding every render, including the ~156 loader ticks). Cross-browser: paired -webkit-backdrop-filter on the showcase CTA. Stale CLAUDE.md notes corrected (BackLink, the CardVideo debt).
  • Verified live: every case page's images and videos decode and serve 200 (webp/mp4), the homepage loader plus 5 walkthroughs load, no console errors. No visible change: the same site, about half the bytes.

2026-07-19 · Work tab rebuilt around umbrellas; interfaces become phone sub-tiles

Deploy: anirudhux-aw9eifdr0-anirudhux.vercel.app

  • Work is four tiles now: 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 instead of a case study.
  • On phone each umbrella folds its interfaces into an inset composite: AI-style cards (40% thumbnail plus play stub plus 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; it stays its own tile ≥601.
  • Design System joins the AI reveal mechanism (tablet shot); the Shape and Design-System tablet shots nudged (object-position) to line up with the laptop screens above and below.
  • Tablet fixes: a slimmer footer, the switch pill clears the last rows, the 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 arrive. I 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 light now (my call): the same composition and IA, the site's own light standards. A 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 passing. 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.
  • The tooltip clash fixed (a 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 follow the same gate (role/aria-expanded were lying on desktop).

2026-07-17 · Hareesh's testimonial arrives

Deploy: anirudhux-60frjtqs9-anirudhux.vercel.app

  • A 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 was not to hand, and the card renders fine without one (Chetan's does too).
  • The avatar cropped from a full-body reference to head-and-shoulders, matching the other avatars' framing: 800×800/172KB → 200×200/12KB.
  • A side effect of INITIAL = 4: Srinivasan now goes behind "Load more".

2026-07-17 · The switch pill tracks the footer instead of dodging it

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

  • The phone and 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 following 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

  • The homepage layout re-railed: an absolute 35/65 column split (the 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, no 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, and 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).
  • The 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 and tablet: the same tooltip, tap-to-toggle, outside-tap or 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 takes the switcher's hairline

Deploy: anirudhux-qubpdxyve-anirudhux.vercel.app

  • The fused Highlights slab's border and painted grout now use the nav switcher's stroke recipe verbatim (hue 30%, 0.5px); my 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 and 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 (a placement bug: heading-keyed figures appended after prose); fresh Constella stills including sunburst and tree, the 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). It had been four independent per-element clocks (two at 9s, two at 18s), which is why the wordmark and the page visibly drifted apart.
  • Every dark petrol stroke (slab border, grout, card hairlines, switcher border and divider, phone pill) now follows the live hue instead of fixed petrol.
  • The switcher's muddy-brown dark surfaces became hue-derived: the 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; the 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: a 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; the 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 is the pitch, Contact is the 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 and avatar at sizes that survive a WhatsApp thumbnail; the anirudhux.com · Ex: footer line.

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

  • The hire-me contact form: Web3Forms delivery (public-safe key, honeypot plus time-trap plus server filtering), no name field, forest-green focus.
  • Contact becomes the site's closing band: a collapsed teaser, measured heights, its own dot field. The petrol slab scoped to Highlights only after it wrongly went sitewide.
  • Testimonials: zebra tint plus "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 is the phone's header on the desktop's body: a bare centered T1 over a dot ground, desktop tiles with icons, curated <br> breaks.
  • Nav pill and wordmark polish: 46px switch, an eased label wipe ≤600, a 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 plus radius, a fixed petrol wash over footage, hero +20%.
  • Tiles: the rest fill becomes a paper-to-family-tint wash; the T1 sheds the tile look entirely (a wall label on a dot ground, the mono /route plate).
  • Constella moves to constella.anirudhux.com, the 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, a viewport-fixed dot ground, page-load nav rises. Highlights joins the same language.
  • Perf: ~12MB shed; webp everywhere, phone footage truly retired.
  • The hire-me refit (avatar hero, authored testimonials), the Work tab dressed, the footer flows at scroll end.

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

  • View state became navigation state: lens and tab addressable in the URL, Back restores the exact view, the loader skips history returns pre-paint.
  • Flat nav plus hover-reveal tiles; the 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), the DARD case study, listing routes parked 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 to v4 in one day: Highlights ⇄ All under a fixed pivot, per-letter identity type-in, the sequenced switch unfold, the meta-card morph.
  • The identity state machine, the Hire Me modal, frost-on-nav, the 28px rails, the slim one-line footer.
  • lib/curation.ts plus /bench born (the owner control surface), the dark-mode a11y overhaul, theme and viewport-aware walkthroughs, one chrome system sitewide plus the legacy purge.

Video Overview