<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hasanboy Marufjonov — writing</title><description>Personal site. Writing on craft, performance, and the web.</description><link>https://hasanboy.com/</link><language>en</language><item><title>Notes on a slow website</title><link>https://hasanboy.com/writing/notes-on-a-slow-website/</link><guid isPermaLink="true">https://hasanboy.com/writing/notes-on-a-slow-website/</guid><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A friend asked me to look at why their personal site felt sluggish on mobile. Two days, a network throttle, and a lot of receipts later — here&apos;s what I found.&lt;/p&gt;
&lt;h2&gt;What actually matters&lt;/h2&gt;
&lt;p&gt;The site shipped 480kb of JS for a page that rendered ten paragraphs of text. None of it was used above the fold. The hero image was 3MB and the wrong dimensions for every device tested.&lt;/p&gt;
&lt;p&gt;Performance is not a vibe. It is the sum of bytes you ship, the number of round-trips you cause, and the work the main thread has to do before paint. Everything else is folklore.&lt;/p&gt;
&lt;h2&gt;What I changed&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Removed two analytics scripts that competed with each other.&lt;/li&gt;
&lt;li&gt;Replaced the hero image with three responsive sources at 1x / 2x / 3x.&lt;/li&gt;
&lt;li&gt;Inlined the critical CSS (~3kb) and lazy-loaded the rest.&lt;/li&gt;
&lt;li&gt;Killed a 90kb webfont that loaded for a single H1.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Outcome&lt;/h2&gt;
&lt;p&gt;First contentful paint dropped from 4.1s to 0.6s on a Moto G4. Lighthouse went from 38 to 96. The site is the same site — it just gets out of its own way now.&lt;/p&gt;
&lt;p&gt;Owners of fast websites have not made a deal with the devil. They just say no a lot.&lt;/p&gt;
</content:encoded><category>perf</category></item><item><title>Container queries, one year later</title><link>https://hasanboy.com/writing/container-queries-one-year-later/</link><guid isPermaLink="true">https://hasanboy.com/writing/container-queries-one-year-later/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A year ago container queries shipped in every browser. I&apos;ve been waiting for an excuse to stop using media queries for component-level layout. Here&apos;s what changed in my workflow.&lt;/p&gt;
&lt;h2&gt;The shift&lt;/h2&gt;
&lt;p&gt;Before: my Card component had three sizes, each with its own media-query&apos;d breakpoint that assumed it knew what the viewport looked like. It didn&apos;t, usually.&lt;/p&gt;
&lt;p&gt;After: the Card asks its own container how wide it is. It restyles itself based on the room it&apos;s actually in. The same component renders differently in a sidebar vs. a full-width grid vs. a modal.&lt;/p&gt;
&lt;h2&gt;What I learned&lt;/h2&gt;
&lt;p&gt;Container queries are not a drop-in replacement for media queries. The page-level layout still belongs to viewport breakpoints — that&apos;s the right tool for &apos;is this a phone or a desktop&apos;.&lt;/p&gt;
&lt;p&gt;Container queries are for components. Use them to make a component robust enough to drop anywhere without rewriting it.&lt;/p&gt;
&lt;h2&gt;A tip&lt;/h2&gt;
&lt;p&gt;Set &apos;container-type: inline-size&apos; on the parent, not the component itself. Otherwise the component can&apos;t measure its own children. This took me an embarrassing amount of time to figure out.&lt;/p&gt;
</content:encoded><category>css</category></item><item><title>On owning your tools</title><link>https://hasanboy.com/writing/on-owning-your-tools/</link><guid isPermaLink="true">https://hasanboy.com/writing/on-owning-your-tools/</guid><pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every craftsperson I admire has at least one tool they made themselves.&lt;/p&gt;
&lt;p&gt;Not because the off-the-shelf one was bad. Because the act of making it taught them how the work actually works.&lt;/p&gt;
&lt;h2&gt;My list&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A markdown notebook that thinks like I think.&lt;/li&gt;
&lt;li&gt;A color-token system that won&apos;t let me typo a hex code.&lt;/li&gt;
&lt;li&gt;A static-site generator small enough to read in a sitting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are better than the popular alternatives. All of them are mine. I know every assumption inside them. When something breaks, I can fix it in five minutes instead of opening an issue and waiting six weeks.&lt;/p&gt;
&lt;h2&gt;Why it matters&lt;/h2&gt;
&lt;p&gt;When you use somebody else&apos;s tool, you absorb their assumptions whether you want to or not. Eventually the tool starts shaping the work instead of the other way around.&lt;/p&gt;
&lt;p&gt;Build the small thing. Use it for a week. Throw it away if it doesn&apos;t help. The point isn&apos;t the artifact — it&apos;s the seeing.&lt;/p&gt;
</content:encoded><category>craft</category></item><item><title>View transitions in anger</title><link>https://hasanboy.com/writing/view-transitions-in-anger/</link><guid isPermaLink="true">https://hasanboy.com/writing/view-transitions-in-anger/</guid><pubDate>Sat, 29 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;View transitions are the first new animation primitive on the web in a decade that actually changes how I design.&lt;/p&gt;
&lt;p&gt;I spent a month using them on a real product, not a demo. Here&apos;s the unglamorous version.&lt;/p&gt;
&lt;h2&gt;What they&apos;re good for&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cross-document persistence: an element that exists on two routes can morph between them.&lt;/li&gt;
&lt;li&gt;Hierarchy reveals: an item in a list becoming the detail view, gracefully.&lt;/li&gt;
&lt;li&gt;Cheap polish: tasteful crossfades cost two lines of CSS now.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What they&apos;re bad at&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Anything stateful underneath the transition. React doesn&apos;t know you&apos;re transitioning, so it keeps doing React things and the morph breaks.&lt;/li&gt;
&lt;li&gt;Long animations. Anything past 400ms starts to feel like waiting.&lt;/li&gt;
&lt;li&gt;Accessibility. Reduced-motion is respected, but the default API doesn&apos;t give you enough hooks to design a graceful fallback.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;My rule&lt;/h2&gt;
&lt;p&gt;If the transition can&apos;t be explained in one sentence — what is changing, and why — it&apos;s the wrong tool.&lt;/p&gt;
</content:encoded><category>web</category></item><item><title>A type system for color</title><link>https://hasanboy.com/writing/a-type-system-for-color/</link><guid isPermaLink="true">https://hasanboy.com/writing/a-type-system-for-color/</guid><pubDate>Sat, 04 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hex codes are an assembly language. They are precise and they are useless for thinking with.&lt;/p&gt;
&lt;p&gt;I want a color system where the names mean something, where the relationships are explicit, and where I cannot write a contrast bug because the types won&apos;t let me.&lt;/p&gt;
&lt;h2&gt;The shape&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A palette is a set of hues at perceptually-uniform lightness steps.&lt;/li&gt;
&lt;li&gt;A token is a (palette, role, mode) triple.&lt;/li&gt;
&lt;li&gt;A theme picks one row from each palette for each mode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once that&apos;s typed, autocomplete becomes the design system.&lt;/p&gt;
&lt;h2&gt;What broke&lt;/h2&gt;
&lt;p&gt;OKLCH made this almost easy. Every step I&apos;d previously eyeballed in HSL became math. The remaining 10% — gamut clipping, browser support, designers who insist on a specific hex — is the boring part.&lt;/p&gt;
&lt;p&gt;I&apos;d rather fight the boring part with types than fight the interesting part with vibes.&lt;/p&gt;
</content:encoded><category>design</category></item><item><title>Stop animating the wrong thing</title><link>https://hasanboy.com/writing/stop-animating-the-wrong-thing/</link><guid isPermaLink="true">https://hasanboy.com/writing/stop-animating-the-wrong-thing/</guid><pubDate>Sun, 17 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most UI animation is decorative. Decorative animation is fine. It&apos;s also expensive — in attention, in performance, in the cost of getting it wrong.&lt;/p&gt;
&lt;p&gt;Before animating anything, ask: what is the user supposed to learn from this motion?&lt;/p&gt;
&lt;p&gt;If the answer is &apos;nothing, it&apos;s just pretty&apos; — leave it out, or make it half as long.&lt;/p&gt;
&lt;p&gt;If the answer is &apos;where this element went&apos; or &apos;that the system heard them&apos; — animate the thing that answers the question and nothing else.&lt;/p&gt;
&lt;h2&gt;The short version&lt;/h2&gt;
&lt;p&gt;Motion is a sentence about cause and effect. Most UI animation is a sentence with no verb.&lt;/p&gt;
</content:encoded><category>motion</category></item><item><title>Why I write my own components</title><link>https://hasanboy.com/writing/why-i-write-my-own-components/</link><guid isPermaLink="true">https://hasanboy.com/writing/why-i-write-my-own-components/</guid><pubDate>Sun, 01 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I have shipped products built on Bootstrap, Material, Chakra, Radix, Headless UI, MUI, Mantine, and a dozen smaller things.&lt;/p&gt;
&lt;p&gt;For my own work I write the components myself. Here is why.&lt;/p&gt;
&lt;h2&gt;The library tax&lt;/h2&gt;
&lt;p&gt;Every component library is an opinion about how UI should work. You inherit the opinions whether you wanted them or not — focus rings, animation curves, ARIA shapes, the bundle size of the framework underneath.&lt;/p&gt;
&lt;p&gt;Most of the time, the opinions are fine. Sometimes they&apos;re great. Occasionally they&apos;re a five-day debugging session with no good answer at the end.&lt;/p&gt;
&lt;h2&gt;What I gain&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Every component I have is one I understand.&lt;/li&gt;
&lt;li&gt;The bundle is whatever I decided to ship.&lt;/li&gt;
&lt;li&gt;I can change the focus ring without writing a PR against somebody else&apos;s repo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What I lose&lt;/h2&gt;
&lt;p&gt;Speed of the first three days. Accessibility primitives I&apos;d have gotten for free. The comfort of a popular Discord.&lt;/p&gt;
&lt;p&gt;I still use libraries on client work. For my own things — small, slow, mine — the trade lands the other way.&lt;/p&gt;
</content:encoded><category>craft</category></item></channel></rss>