<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mateusz Muszarski</title>
    <description>The latest articles on DEV Community by Mateusz Muszarski (@muchassak).</description>
    <link>https://dev.to/muchassak</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4177825%2F9516f0c3-66c5-4ba9-9fd0-d47ef79cee4b.jpg</url>
      <title>DEV Community: Mateusz Muszarski</title>
      <link>https://dev.to/muchassak</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/muchassak"/>
    <language>en</language>
    <item>
      <title>Astro vs Next.js for a portfolio or a landing page</title>
      <dc:creator>Mateusz Muszarski</dc:creator>
      <pubDate>Mon, 12 Oct 2026 07:47:58 +0000</pubDate>
      <link>https://dev.to/muchassak/astro-vs-nextjs-for-a-portfolio-or-a-landing-page-4jpf</link>
      <guid>https://dev.to/muchassak/astro-vs-nextjs-for-a-portfolio-or-a-landing-page-4jpf</guid>
      <description>&lt;p&gt;&lt;em&gt;This post first appeared on &lt;a href="https://muszarski.com/en/blog/astro-vs-nextjs-for-a-portfolio/" rel="noopener noreferrer"&gt;my site&lt;/a&gt;, where the clips play and the version tabs work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a portfolio or a landing page, Astro is the better default: it pre-renders every page to HTML and ships no JavaScript unless a component asks for it. Next.js is the better call when the site is really an application, with logins, per-user data and server-side writes. This site is Astro; Clockful, the time tracker I built during my internship at Neoteric, is Next.js.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Astro for content:&lt;/strong&gt; every page pre-rendered to HTML, zero JavaScript by default, interactivity opted into per island.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js for apps:&lt;/strong&gt; logins, roles and per-user data; its static export gives up cookies, redirects, Server Actions and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public data:&lt;/strong&gt; in HTTP Archive's August 2026 mobile data, 71.0% of Astro origins pass Core Web Vitals against 35.1% of Next.js origins, partly because people build different things with each.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What does each framework say it is for?
&lt;/h2&gt;

&lt;p&gt;Astro's docs are direct: "Astro is the web framework for building content-driven websites like blogs, marketing, and e-commerce." It calls itself server-first, with zero JavaScript by default. The same page says other frameworks "excel at building more complex, application-like experiences in the browser: logged-in admin dashboards, inboxes, social networks, todo lists".&lt;/p&gt;

&lt;p&gt;Next.js calls itself "a React framework for building full-stack web applications". In its App Router, layouts and pages are React Server Components by default, and you opt into client code with the &lt;code&gt;"use client"&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;Those two lines answer most of the question. A portfolio is a content site with a contact form. A dashboard is an application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much JavaScript reaches the browser?
&lt;/h2&gt;

&lt;p&gt;In Astro, every UI component, React included, renders to HTML and CSS, and its client JavaScript is stripped out. Interactivity is opt-in per component, through islands: &lt;code&gt;client:load&lt;/code&gt; hydrates at once, &lt;code&gt;client:idle&lt;/code&gt; when the browser is idle, &lt;code&gt;client:visible&lt;/code&gt; when the component scrolls into view. A page without islands ships no framework runtime.&lt;/p&gt;

&lt;p&gt;Next.js renders on the server too, and Server Components keep their code out of the bundle. The client still runs React, though, to hydrate Client Components and handle client-side navigation, and everything a &lt;code&gt;"use client"&lt;/code&gt; file imports joins the bundle. That pays off in an app with many screens and shared state; on a five-page portfolio it is overhead to manage.&lt;/p&gt;

&lt;p&gt;Here is the Astro path on this site:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build.&lt;/strong&gt; Every page becomes HTML, with its CSS inlined in the head.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN.&lt;/strong&gt; Vercel serves the files; the contact form is the one function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text first.&lt;/strong&gt; The H1 is the largest paint and waits for no script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small scripts.&lt;/strong&gt; Component scripts load as small modules, with no framework runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effects last.&lt;/strong&gt; Loops and clips wait for the first interaction; shaders draw only in view.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are no framework islands here at all. Every component is an &lt;code&gt;.astro&lt;/code&gt; file, and the interactive parts (the pause button, the credentials tour, the writing rail) are plain scripts that Astro bundles into small modules. On the home page they come to under 10 KB, gzipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can both produce a static site?
&lt;/h2&gt;

&lt;p&gt;Yes, at a different cost. Astro's default is static: "By default, your entire Astro site will be prerendered". If one route needs a server, such as a contact endpoint, you add an adapter and mark that page with &lt;code&gt;export const prerender = false&lt;/code&gt;. Everything else stays static.&lt;/p&gt;

&lt;p&gt;This site skipped even that: no adapter, and the contact form posts to a plain Vercel Function next to the static files (&lt;a href="https://muszarski.com/en/blog/contact-form-on-a-static-site/" rel="noopener noreferrer"&gt;how the contact form works&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Next.js can produce a static site too: with &lt;code&gt;output: 'export'&lt;/code&gt;, &lt;code&gt;next build&lt;/code&gt; writes one HTML file per route into an &lt;code&gt;out&lt;/code&gt; folder. The docs list what you give up, including cookies, redirects, Proxy, Incremental Static Regeneration, Server Actions and dynamic routes without &lt;code&gt;generateStaticParams()&lt;/code&gt;. Many of those are the reason to pick Next.js in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about content, translations and page transitions?
&lt;/h2&gt;

&lt;p&gt;A portfolio is mostly writing. Astro's content collections load Markdown and MDX from folders, validate frontmatter with a Zod schema and generate TypeScript types from it. This post is one of those files: its title, description and sources are checked before the page builds. The site's three languages run on Lingui, all of it static (&lt;a href="https://muszarski.com/en/blog/multilingual-astro-site-with-lingui/" rel="noopener noreferrer"&gt;how the multilingual setup works&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For page transitions, Astro supports the browser's native cross-document view transitions (the CSS &lt;code&gt;@view-transition&lt;/code&gt; rule), and its &lt;code&gt;&amp;lt;ClientRouter /&amp;gt;&lt;/code&gt; adds SPA-style ones when you want more control. This site uses only the CSS rule: pages crossfade with no JavaScript, and readers who ask for reduced motion navigate instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does public data say?
&lt;/h2&gt;

&lt;p&gt;The HTTP Archive Tech Report takes real-user Core Web Vitals from the Chrome UX Report per origin, and detects technologies on each site's home page and one inner page. Astro and Next.js in the August 2026 dataset, mobile, all origins:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mobile, August 2026&lt;/th&gt;
&lt;th&gt;Astro&lt;/th&gt;
&lt;th&gt;Next.js&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Origins assessed&lt;/td&gt;
&lt;td&gt;43,850&lt;/td&gt;
&lt;td&gt;374,612&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good Core Web Vitals (LCP, INP, CLS)&lt;/td&gt;
&lt;td&gt;71.0%&lt;/td&gt;
&lt;td&gt;35.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good LCP&lt;/td&gt;
&lt;td&gt;80.6%&lt;/td&gt;
&lt;td&gt;53.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median JavaScript per page&lt;/td&gt;
&lt;td&gt;405 KB&lt;/td&gt;
&lt;td&gt;853 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read it as a picture of two populations, not a verdict on two frameworks. By their own docs, Next.js targets applications and Astro targets content sites, so part of the gap is what people build with each. The report can't separate a framework from the site built on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did this site measure?
&lt;/h2&gt;

&lt;p&gt;This site is Astro 7, Tailwind 4 and one variable font, served as static files from Vercel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokdfev9ts7fcrh63n8oz.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokdfev9ts7fcrh63n8oz.webp" alt="A Lighthouse report for the home page on mobile: four green gauges for Performance, Accessibility, Best Practices and SEO, next to a phone preview of the hero"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The home page in Lighthouse on mobile, from a local production build on 7 October 2026. The CV, blog and work pages score 96 to 100 on the same setup.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Two honest notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I did not build the same site in Next.js,&lt;/strong&gt; so I can't tell you what it would have scored. That is why the comparison above uses public data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The framework didn't earn the score alone.&lt;/strong&gt; On the afternoon of 7 October the home page fell to 67-74 with no framework code involved: animation loops running during load, a class that restyled every element in the offscreen sections, and scripts forcing layouts. Fixing those brought it back. What Astro gave me is the starting point: zero JavaScript, so there was nothing to remove.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same pattern shows up in &lt;a href="https://muszarski.com/en/blog/lighthouse-scores-of-16-developer-portfolios/" rel="noopener noreferrer"&gt;Lighthouse runs on 16 developer portfolios&lt;/a&gt;: the immersive 3D sites scored far below the minimal ones. The whole build story is in &lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;how this site was built&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since then I have measured one real move: yws.lu, a client site I built in Next.js in 2025. It scored 23-45 on Lighthouse performance, and 94-100 after the rebuild in Astro (Lighthouse 13.5, local, the median of 3 runs). The details are in &lt;a href="https://muszarski.com/en/blog/yws-lu-case-study/" rel="noopener noreferrer"&gt;the yws.lu case study&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is Next.js the right call?
&lt;/h2&gt;

&lt;p&gt;Pick Next.js when most screens depend on who is looking at them. Clockful, the role-based time tracker from my internship at Neoteric, is that kind of project: logins, roles, per-user data, and Postgres row-level security on every table.&lt;/p&gt;

&lt;p&gt;The Next.js docs cover that ground in one guide: authentication, sessions in cookies, authorization in a data access layer, and Server Actions for writes. Astro can render on demand too, but its own docs point to other frameworks for logged-in dashboards. Next.js also wins when the landing page belongs to an existing Next.js product: one codebase beats two stacks for one marketing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is Astro the right call?
&lt;/h2&gt;

&lt;p&gt;When the site is content first: a portfolio, a landing page, docs, a blog, a small business site. You can still write React, Preact, Svelte, Vue or SolidJS where you need interactivity, and only those islands ship code. Hosting is a CDN plus a build, with a server function only where you need one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one fits your kind of site?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your site&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Portfolio, CV, blog&lt;/td&gt;
&lt;td&gt;Astro&lt;/td&gt;
&lt;td&gt;Static HTML, zero JS by default, content collections&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketing landing page&lt;/td&gt;
&lt;td&gt;Astro&lt;/td&gt;
&lt;td&gt;Same, plus an island for the one interactive widget&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Landing page inside a Next.js product&lt;/td&gt;
&lt;td&gt;Next.js&lt;/td&gt;
&lt;td&gt;One codebase, one deploy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard with logins and roles&lt;/td&gt;
&lt;td&gt;Next.js&lt;/td&gt;
&lt;td&gt;Server Components, auth guide, Server Actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App with per-user data on every screen&lt;/td&gt;
&lt;td&gt;Next.js&lt;/td&gt;
&lt;td&gt;Built for on-demand rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content site with one or two dynamic routes&lt;/td&gt;
&lt;td&gt;Astro&lt;/td&gt;
&lt;td&gt;Static by default, &lt;code&gt;prerender = false&lt;/code&gt; per route&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How do you decide for your project?
&lt;/h2&gt;

&lt;p&gt;Write down what the site must do in its first year. If the list says "log in", "dashboard" or "per-user data", start with Next.js. If it says "pages, posts, a contact form", start with Astro, then measure on a mid-range phone.&lt;/p&gt;

&lt;p&gt;The rest of what I've built is on my &lt;a href="https://muszarski.com/en/work/" rel="noopener noreferrer"&gt;work page&lt;/a&gt;; Clockful, the role-based app, is on my &lt;a href="https://muszarski.com/en/cv/" rel="noopener noreferrer"&gt;CV&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/concepts/why-astro/" rel="noopener noreferrer"&gt;Astro docs: Why Astro?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/concepts/islands/" rel="noopener noreferrer"&gt;Astro docs: Islands architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/guides/on-demand-rendering/" rel="noopener noreferrer"&gt;Astro docs: On-demand rendering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/guides/content-collections/" rel="noopener noreferrer"&gt;Astro docs: Content collections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/guides/view-transitions/" rel="noopener noreferrer"&gt;Astro docs: View transitions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js docs: Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/getting-started/server-and-client-components" rel="noopener noreferrer"&gt;Next.js docs: Server and Client Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/guides/static-exports" rel="noopener noreferrer"&gt;Next.js docs: Static exports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/guides/authentication" rel="noopener noreferrer"&gt;Next.js docs: Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httparchive.org/reports/techreport/landing" rel="noopener noreferrer"&gt;HTTP Archive Tech Report: about the data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httparchive.org/reports/techreport/tech?tech=Astro,Next.js" rel="noopener noreferrer"&gt;HTTP Archive Tech Report: Astro vs Next.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;How this post was made: I wrote it with Claude Code. It drafted the text from my project's wiki, code and notes. Just a quick disclaimer for y'all out there :)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>astro</category>
      <category>performance</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Hello Wor-- I mean, Hello dev.to :)</title>
      <dc:creator>Mateusz Muszarski</dc:creator>
      <pubDate>Sun, 11 Oct 2026 21:38:00 +0000</pubDate>
      <link>https://dev.to/muchassak/hello-wor-i-mean-hello-devto--fdn</link>
      <guid>https://dev.to/muchassak/hello-wor-i-mean-hello-devto--fdn</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg" class="crayons-story__hidden-navigation-link"&gt;Trying to build an Awwwards-winning brutalist portfolio: the process, the mindset and the tools&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/muchassak" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4177825%2F9516f0c3-66c5-4ba9-9fd0-d47ef79cee4b.jpg" alt="muchassak profile" class="crayons-avatar__image" width="460" height="460"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/muchassak" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mateusz Muszarski
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mateusz Muszarski
                
                
              
              &lt;div id="story-author-preview-content-4834606" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/muchassak" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4177825%2F9516f0c3-66c5-4ba9-9fd0-d47ef79cee4b.jpg" class="crayons-avatar__image" alt="" width="460" height="460"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mateusz Muszarski&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Oct 11&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg" id="article-link-4834606"&gt;
          Trying to build an Awwwards-winning brutalist portfolio: the process, the mindset and the tools
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/showdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;showdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/astro"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;astro&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/performance"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;performance&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            16 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>design</category>
      <category>frontend</category>
      <category>portfolio</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Trying to build an Awwwards-winning brutalist portfolio: the process, the mindset and the tools</title>
      <dc:creator>Mateusz Muszarski</dc:creator>
      <pubDate>Sun, 11 Oct 2026 21:08:59 +0000</pubDate>
      <link>https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg</link>
      <guid>https://dev.to/muchassak/trying-to-build-an-awwwards-winning-brutalist-portfolio-the-process-the-mindset-and-the-tools-4njg</guid>
      <description>&lt;p&gt;&lt;em&gt;This post first appeared on &lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;my site&lt;/a&gt;, where the clips play and the version tabs work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My old portfolio was a WebGL flight from Earth to Neptune. It looked great on my desktop. On a phone it showed an “Oops!” screen. This is the story of swapping it for a poster: the versions, the research, the sites I learned from and the reasons behind each call, mostly in pictures.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/bUbHtUvuzpI" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How this site got built, in 47 seconds. Made in code with Claude Code: the real site filmed frame by frame, and music written in code.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before:&lt;/strong&gt; a 3D site that scored 34 on mobile Lighthouse and didn't work on phones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After:&lt;/strong&gt; Astro, three languages, one font, a few shaders that never get in the way, and 95 to 100 on mobile Lighthouse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How:&lt;/strong&gt; a project wiki before any code, research on award winners and real products, four live designs to pick from, and checks on every change.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What rules did I work by?
&lt;/h2&gt;

&lt;p&gt;Six rules: most written down before the first line of code, the rest learned on the way. Everything below follows from them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plan before code.&lt;/strong&gt; The project lives in a wiki that every AI session reads first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practical first, then wow.&lt;/strong&gt; Impressive within 3 seconds, usable in one tap on a phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research, then pick.&lt;/strong&gt; Real sites and real screens first; I choose between live options, not sketches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show, don't tell.&lt;/strong&gt; A picture or a moving demo wherever a paragraph would go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep every version.&lt;/strong&gt; So I can show how it changed, and go back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing ships unchecked.&lt;/strong&gt; Tests, screenshots I look at myself, speed on a slow phone.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How did it go, version by version?
&lt;/h2&gt;

&lt;p&gt;About four days, and every version is kept.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before: The 3D space portfolio&lt;/strong&gt; (Replaced)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2e65n58dbovd3mczavrr.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2e65n58dbovd3mczavrr.webp" alt="The old site: a glowing planet and the word Projects in space" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A WebGL flight to Neptune. Beautiful on my desktop, an “Oops!” screen on phones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Oct 2026: Phase 0: a wiki, no code&lt;/strong&gt; (Kept)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plan first, code second.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Research, requirements, brand, legal and the rules of the project, before a single component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Oct 2026: Drafting Table&lt;/strong&gt; (Rejected)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0gek711p8jmoeo114yni.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0gek711p8jmoeo114yni.webp" alt="The first design: a pale paper page with a blueprint grid and a small heading" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A clean system is not a good design.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Paper, cyanotype and a title-block header. It passed every check and looked forgettable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Oct 2026: Four live directions&lt;/strong&gt; (Poster picked)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbsyykkjj6vqbe6eqlx3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbsyykkjj6vqbe6eqlx3.webp" alt="The Poster direction: the name in huge white capitals on cobalt with a pink round sticker" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The type is the picture.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Orbit, Poster, Toybox and Exhibit as working pages. Claude recommended Orbit. I picked Poster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Oct 2026: Round 2: Poster everywhere&lt;/strong&gt; (Notes)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbtfbttxd4eujadba1vna.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbtfbttxd4eujadba1vna.webp" alt="Round 2 of Poster: the contact section, Let's talk in huge capitals on pink" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole home page in Poster, three colour themes and two fonts tried side by side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 Oct 2026: Round 3: less text&lt;/strong&gt; (Approved)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx11fk0l4g1leeatuisht.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx11fk0l4g1leeatuisht.webp" alt="Round 3 of Poster: credentials as tall cards with sideways titles, one open" width="799" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Less text, more to see.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Tool logos with their names, a reel per project, a shorter everything. The comps stop here and the real code starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6-8 Oct 2026: The site today&lt;/strong&gt; (Live)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbt1lxq2n16wpq1kskah5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbt1lxq2n16wpq1kskah5.webp" alt="Today's hero: the name fitted edge to edge on cobalt, the role and two buttons" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built in Astro one section at a time, then reshaped by rounds of my notes on the live site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why rebuild it?
&lt;/h2&gt;

&lt;p&gt;Here is the old portfolio in motion:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfguqvo09pohcgex7f40.webp" alt="The old space portfolio: the camera flies past Mars to Jupiter" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The 3D space portfolio, recorded on a desktop. Planet textures: Solar System Scope, CC BY 4.0.&lt;/em&gt; The clips play on &lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;the original post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Beautiful on my desktop. Then I measured it, on 5 October 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;13.8 MB before the start button.&lt;/strong&gt; 7.6 MB of it was an emoji font.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;34 on mobile Lighthouse.&lt;/strong&gt; On a throttled phone the main content took 46.9 seconds to appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phones got an “Oops!” screen.&lt;/strong&gt; The site didn't run there at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only a mouse wheel moved it.&lt;/strong&gt; No touch swipe, no keyboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing for search engines.&lt;/strong&gt; The raw HTML had no text to index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Someone opening a portfolio from a LinkedIn message on a phone gives it maybe ten seconds. My old site spent them on a loading bar. It proved I can write shaders; it also proved I hadn't thought about the person on the other side.&lt;/p&gt;

&lt;p&gt;So no preloader, no gate, no scroll-jacking, and the same content on every screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a portfolio for?
&lt;/h2&gt;

&lt;p&gt;Showing your work. It sounds obvious, yet many portfolios bury the visitor under “about me” paragraphs, or pitch their tech stack as if it were sacred, and the projects end up three scrolls down. Here the projects come right after the name: “See the work” is the first button, the tools are one strip of logos, and the about-me has a page of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  How did the planning work?
&lt;/h2&gt;

&lt;p&gt;Before any code, I wrote the project down in a wiki of markdown pages: the audience, the brand, the budgets, the legal texts. The idea comes from Andrej Karpathy's &lt;a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f" rel="noopener noreferrer"&gt;LLM Wiki&lt;/a&gt;: the AI keeps the wiki up to date itself, so what it learns builds up. Three Claude Code hooks put the right pages in front of every session:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Session starts.&lt;/strong&gt; The working rules and the lessons load first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each prompt.&lt;/strong&gt; A hook names the wiki pages the task needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The work.&lt;/strong&gt; Claude Code builds and checks with those pages open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turn ends.&lt;/strong&gt; If the code changed and the wiki didn't, the turn stops once.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;↻ A mistake becomes a one-line lesson, and the next session starts with it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;More in &lt;a href="https://muszarski.com/en/blog/llm-wiki-project-memory-for-claude-code/" rel="noopener noreferrer"&gt;An LLM wiki: project memory for Claude Code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did the research show?
&lt;/h2&gt;

&lt;p&gt;Agents opened 20 developer portfolios that won Awwwards awards in 2023-2026, on a desktop and on a throttled phone (1.6 Mbps, a 4× slower CPU). Each got two scores from 1 to 5: &lt;strong&gt;Wow&lt;/strong&gt; for how memorable it is, and &lt;strong&gt;Practicality&lt;/strong&gt; for how fast you can reach the projects and the contact. Practicality was measured as the moment the first real link becomes clickable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;20 award-winning portfolios by Wow and Practicality (one run each, 5 October 2026)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Site&lt;/th&gt;
&lt;th&gt;Practicality&lt;/th&gt;
&lt;th&gt;Wow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Edoardo Lunardi&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clément Grellier&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Elliott Mangham&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valentin Mor&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Antoine Wodniack&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jesper Landberg&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stefan Vitasović&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grégory Lallé&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rafa de las Heras&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hiroto Sato&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ravi Klaassens&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abhishek Jha&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Francesco Michelini&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lusion (studio)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max Milkin&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Corentin Bernadou&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kris Temmerman&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bruno Simon&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Samsy&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jordan Delcros&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Both scores 4 or more: only 4 of 20 sites&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What came out of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An award doesn't mean usable.&lt;/strong&gt; On the throttled phone only 8 of the 20 were usable within 3 seconds, and 9 weren't usable within 10. The four least practical (game worlds and gated intros) even had a higher average Site of the Day score than the three most practical ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The jury isn't hiring.&lt;/strong&gt; Awwwards weighs design 40%, usability 30%, creativity 20% and content 10%, and the jurors are designers and developers. A recruiter asks one thing: can I find the projects and the contact?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stunning and practical is possible, but rare.&lt;/strong&gt; Only four sites scored 4 or more on both. What they share: real links on the first screen, and the show beside the content, never in front of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what that looks like on a phone. First, the immersive end:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe12zzwuduuw6rpet1iec.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe12zzwuduuw6rpet1iec.webp" alt="Bruno Simon's portfolio on a phone: a small 3D car in a purple world and the words Click to start" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Bruno Simon: Click to start&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fblg07shnsb3cwhmmt0ub.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fblg07shnsb3cwhmmt0ub.webp" alt="Samsy's portfolio on a phone: a dark screen with a glowing red robot and no links" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Samsy: No links in the HTML&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiktawzmbmecxxb7wg81y.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiktawzmbmecxxb7wg81y.webp" alt="Jordan Delcros's portfolio on a phone: a black screen with a thin loading bar" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jordan Delcros: About 20 s of loading&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Three of the most memorable sites in the study, on the throttled phone (5 October 2026). Quoted for review; the sites belong to their authors: bruno-simon.com, samsy.ninja, jordan-delcros.com.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And the four that did both. Each one gave this site an idea:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4zwajgmxppzycq8xhws.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx4zwajgmxppzycq8xhws.webp" alt="Edoardo Lunardi's portfolio on a phone: desktop-style windows with an About text, links and a work gallery" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Edoardo Lunardi: Real links on the first screen&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8jfaz7mb0r4jih79i4h.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8jfaz7mb0r4jih79i4h.webp" alt="Jesper Landberg's portfolio on a phone: a vertical list of project cards" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Jesper Landberg: The show beside the content&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygp1zklnhfedu0d6mhy4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fygp1zklnhfedu0d6mhy4.webp" alt="Antoine Wodniack's portfolio on a phone: red wavy lines, the words Creative Developer and a Hire me button in the header" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Antoine Wodniack: Hire me in the header&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8jysnzyq0jm2t8g97byh.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8jysnzyq0jm2t8g97byh.webp" alt="Stefan Vitasović's portfolio on a phone: big type cut by grey redaction bars" width="600" height="1298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stefan Vitasović: One signature effect&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stunning and practical, and what I took from each. Quoted for review; the sites belong to their authors: edoardolunardi.dev, jesperlandberg.com, wodniack.dev, stefanvitasovic.dev.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Section ideas came from &lt;a href="https://mobbin.com/" rel="noopener noreferrer"&gt;Mobbin&lt;/a&gt;, a library of real screens from shipped products. The topic chips above my contact form are one of them: you start with a tap, not a blank field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not another 3D world?
&lt;/h2&gt;

&lt;p&gt;Honestly, I love them. My last portfolio was one. But I had measured both kinds of site by then, and the trade looked like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;A full 3D world&lt;/th&gt;
&lt;th&gt;This site&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First screen&lt;/td&gt;
&lt;td&gt;a loader or “click to start”&lt;/td&gt;
&lt;td&gt;my name, my role and two buttons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Links&lt;/td&gt;
&lt;td&gt;often none in the HTML (Samsy, Jordan Delcros)&lt;/td&gt;
&lt;td&gt;every link is real HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search engines and screen readers&lt;/td&gt;
&lt;td&gt;text drawn in WebGL is invisible to them&lt;/td&gt;
&lt;td&gt;real text, painted first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slow phone&lt;/td&gt;
&lt;td&gt;9 of 20 award winners unusable within 10 s&lt;/td&gt;
&lt;td&gt;shaders start after the text, only while visible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No WebGL or WebGPU&lt;/td&gt;
&lt;td&gt;an error instead of the site (Kris Temmerman)&lt;/td&gt;
&lt;td&gt;a CSS picture underneath&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So the wow stays, as a layer instead of a gate. Four shaders run on this site, all written for it with no library:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fyc4vxy7m6w2pzv7pp5.webp" alt="The All projects head: a dithered cloud of colour gathers behind a wall of project tiles and takes the colour of the tile under the pointer" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dither field&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7zp7sprr6x6baxsryvqr.webp" alt="The footer: faint contour lines drift under the links and rise under the pointer" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Contour lines&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fme1o2dkph8v10u1fothc.webp" alt="Hobby prints on My life: picking a hobby wipes a new two-ink riso print in dot by dot" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Riso prints&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjupkyq9oajdsfcfg6nm.webp" alt="The My life head: a colourful goo behind the title swells when poked" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Goo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A dither field on All projects, contour lines in every footer, riso prints and goo on My life. Each starts after the text is on screen, runs only while visible, and holds still for reduced motion or the pause button.&lt;/em&gt; The clips play on &lt;a href="https://muszarski.com/en/blog/case-study/" rel="noopener noreferrer"&gt;the original post&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I run the AI?
&lt;/h2&gt;

&lt;p&gt;Like a small team. I brief the lead agent, subagents research in parallel, MCP servers bring real data, hooks guard the risky commands, checks gate the result, and I review it. The AI does a lot of the typing; I own the decisions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;On the home page: Watch one change, step by step&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same process as a live story: who works on each step and what it looks like. &lt;a href="https://muszarski.com/en/#ai" rel="noopener noreferrer"&gt;See the seven steps&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The building blocks are in &lt;a href="https://muszarski.com/en/blog/claude-code-skills-hooks-mcp-subagents/" rel="noopener noreferrer"&gt;Claude Code skills, hooks, MCP servers and subagents&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened to the first design?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0gek711p8jmoeo114yni.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0gek711p8jmoeo114yni.webp" alt="The rejected first design: a pale paper page with a faint grid, a small heading and a boxed contact block" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafting Table, the first look. It passed every test and nobody would remember it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So Claude built four very different directions as live pages. It recommended Orbit. I picked Poster: brutalism with manners. Flat saturated colour, hard offset shadows, square buttons and type fitted edge to edge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkxuj7j1pn1nb2zap4r12.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkxuj7j1pn1nb2zap4r12.webp" alt="Orbit: the name over a particle planet" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Orbit: Claude's pick&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbsyykkjj6vqbe6eqlx3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flbsyykkjj6vqbe6eqlx3.webp" alt="Poster: the name in huge capitals on cobalt" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Poster: My pick&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvw4nm47u9do8k17v02bt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvw4nm47u9do8k17v02bt.webp" alt="Toybox: soft 3D toy shapes next to the name" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Toybox&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwic51u7o52fl02mhuea5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwic51u7o52fl02mhuea5.webp" alt="Exhibit: the name in a serif over a dark red glow" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Exhibit&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In Poster the type itself is the picture, so the design is already there at first paint.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How did each part change, and why?
&lt;/h2&gt;

&lt;p&gt;Six parts of the site through their versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The AI section
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Round 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdb9wy6w6ie9p81qexa34.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdb9wy6w6ie9p81qexa34.webp" alt="Round 2: the heading Delegate. Verify. next to a checklist of gates" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A checklist of gates. All true, and all the floor. It sold the checks, not the way I work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx5jtm7rxejbplrt3ehm.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx5jtm7rxejbplrt3ehm.webp" alt="Round 3: the heading Delegate. Automate. above a row of counters for hooks, wiki pages, subagents, MCP servers, skills and lessons" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Counters for hooks, pages and agents. Numbers that change every week and say nothing about the work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwi1veju3c91fimonhxtw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwi1veju3c91fimonhxtw.webp" alt="Now: I run AI like a team. The team of me and six agents above seven numbered steps, with step 5, Build, open: a terminal where a force push is stamped Blocked" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Show how the work gets done, not how much of it there is.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One change in seven steps, from my brief to my review, each with a small drawn scene.&lt;/p&gt;

&lt;h3&gt;
  
  
  Competences (once Credentials)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Round 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyrnteckmrrqoaxo6r5d.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyrnteckmrrqoaxo6r5d.webp" alt="Round 2: a grid of seven credential cards, each with a paragraph" width="799" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seven cards, each a paragraph. Everything visible, nothing readable at a glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx11fk0l4g1leeatuisht.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx11fk0l4g1leeatuisht.webp" alt="Round 3: tall collapsed cards with vertical titles and one card open with a picture" width="799" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sideways titles that open on hover. Compact, and hard to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdgbzaqjz7ia2di1g07rt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdgbzaqjz7ia2di1g07rt.webp" alt="Now: a readable list on the left and the Experience card open on the right, with school and three internships as tickets" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Experience first, and every certificate checkable.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A list on the left, one open card on the right, a link to check every certificate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contact
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Round 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbtfbttxd4eujadba1vna.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbtfbttxd4eujadba1vna.webp" alt="Round 2: Let's talk, with an email field, a message field and a row of buttons" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A normal form, and every field is a reason to stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5falsk1e5oyo2girmfw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5falsk1e5oyo2girmfw.webp" alt="Round 3: Let's talk, with one message box and three topic chips" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As few fields as possible.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Message first. The reply field appears once you start typing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjlatjmdtrajx5jqsuo4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjlatjmdtrajx5jqsuo4.webp" alt="Now: Let's talk, with topic chips, a message box, a Send button and three direct links" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste an email, a phone number or a LinkedIn link and the reply field fills itself. It works without JavaScript too.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I work
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Round 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggpuqiteacpkxemvwrgt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fggpuqiteacpkxemvwrgt.webp" alt="Round 2: How I work as four numbered principles with small receipts" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four principles as numbered lines. Easy to write, easy to skip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn06zzilzcnqh1in4kizk.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn06zzilzcnqh1in4kizk.webp" alt="Now: Product engineer, a ring of seven stops from client to review, and an open stop with a drawn scene of a shop and a goal, budget and deadline checklist" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tell it as a story you can see.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A ring of seven stops, each with a drawn scene and a real example.&lt;/p&gt;

&lt;h3&gt;
  
  
  All projects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TV&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6n1405tedgnvd3n2yxb5.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6n1405tedgnvd3n2yxb5.webp" alt="The TV version: the heading All my projects, ON AIR, next to a yellow retro TV showing Linkoglot, above project cards in bright colours" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A retro TV flipping through the projects, and a drawn scene wherever there was nothing to film. Fun, but too much of it: it looked vibe coded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Night&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6hw0yu5kst40w4w1qka.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv6hw0yu5kst40w4w1qka.webp" alt="The night version: the heading Things I've built over contour lines, a numbered list of projects on the right, and project plates staggered left and right below" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One dark field, a contour map under the title, plates staggered left and right and an X-ray lens over every capture. Calmer, and hard to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4tma5q1806rck8nzx64.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo4tma5q1806rck8nzx64.webp" alt="Now: the heading Things I've built next to a tilted wall of project tiles over a dithered blue and pink glow, above a grid of project cards on a light background" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Easy to scan first, then the show.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A wall of every project to jump from, then a plain grid of cards on a light field. The contour lines moved to the footer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blog covers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbefjn1jv820jgpj1ay6c.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbefjn1jv820jgpj1ay6c.webp" alt="Six old covers: a stack of papers, two bar charts, a row of boxes, a shield, the letters A A a, and EN and PL bubbles" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Colours came from the card's place in the list, so a post changed colour between pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9c3i90h4rjavwu5vi2tl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9c3i90h4rjavwu5vi2tl.webp" alt="Six new covers: linked wiki pages, a level scale, a terminal wired to helpers, a crossed-out cookie next to bars, one wide letter between two walls, and two swapped speech bubbles" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One palette per cover, and the topic drawn literally.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A scale for a comparison, a crossed-out cookie for cookieless analytics. No words.&lt;/p&gt;

&lt;p&gt;The rule behind all six: show the thing, cut the paragraph.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do the other pages look like?
&lt;/h2&gt;

&lt;p&gt;Every page gets the same care as the home page, on a laptop and on a phone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j801c2vh0oghwkb3562.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j801c2vh0oghwkb3562.webp" alt="All projects: the heading Things I've built next to a tilted wall of project tiles over a dithered blue and pink glow" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All projects&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F465vm3yv9gmvdnmy2sjq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F465vm3yv9gmvdnmy2sjq.webp" alt="My life: the words My life in huge outlined capitals over a colourful blob, next to a stack of holiday photos" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;My life&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhy5p23jnh4p40u4wczv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhy5p23jnh4p40u4wczv.webp" alt="The CV page: the name in huge capitals on cobalt, a photo, the role and a Download PDF button next to the printed CV" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CV&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flu599iu8fk7xockar1vl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flu599iu8fk7xockar1vl.webp" alt="The blog: the word Blog in huge capitals on cobalt above search, kind, topic and sort filters" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Blog&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All projects, My life, the CV and the blog at 1440 px.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvk2grzpyt2snxjx1lq5v.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvk2grzpyt2snxjx1lq5v.webp" alt="Four phone screens side by side: the home page, All projects, My life and the CV" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The same site on a phone: home, All projects, My life and the CV. Same content, one column.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the small details?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The name fills the screen without JavaScript.&lt;/strong&gt; At build time a script measures the font and works out the exact width for each line, so the name fits edge to edge before any script runs (&lt;a href="https://muszarski.com/en/blog/fit-text-to-width-at-build-time/" rel="noopener noreferrer"&gt;how it works&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7r2o37fshyd6ebgls1ym.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7r2o37fshyd6ebgls1ym.webp" alt="The home page at three widths side by side: a phone, a tablet and a wide desktop, each with the name filling the width" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The home page at 390, 1024 and 1920 pixels.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phones get the same site.&lt;/strong&gt; Every hover effect has a twin for touch (&lt;a href="https://muszarski.com/en/blog/hover-effects-on-phones/" rel="noopener noreferrer"&gt;how&lt;/a&gt;), and the contact form has its own write-up, bug included (&lt;a href="https://muszarski.com/en/blog/contact-form-on-a-static-site/" rel="noopener noreferrer"&gt;a contact form on a static site&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Who else is it built for?
&lt;/h2&gt;

&lt;p&gt;Everyone, including people who use the web differently. A site that only works with a mouse and perfect eyesight shuts people out, and I'd rather it didn't. So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Motion you can stop.&lt;/strong&gt; One “Pause motion” button stops everything, and with reduced motion turned on, everything shows its final state (&lt;a href="https://muszarski.com/en/blog/reduced-motion-and-a-pause-button/" rel="noopener noreferrer"&gt;how that works&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A keyboard gets everywhere.&lt;/strong&gt; A skip link jumps past the header, every hover has a focus twin, and focus never hides under the sticky header.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen readers hear the full story.&lt;/strong&gt; Hidden text adds what the eye gets from context, like “opens in a new tab”, and every button's name starts with the words you see on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contrast is tested, not eyeballed.&lt;/strong&gt; A unit test checks every colour pair, and axe runs on every page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do search engines know who I am?
&lt;/h2&gt;

&lt;p&gt;Sitemaps and meta tags are the floor. To find me by name, and one day show a knowledge panel, a search engine has to be sure who the site is about. So every page tells it the same story:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One person, one id.&lt;/strong&gt; The home page and the CV describe me as one &lt;code&gt;Person&lt;/code&gt; in structured data: my name, my role, my real portrait and my profiles. Every post and My life point back to it, and the links to my profiles carry &lt;code&gt;rel="me"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real photos with real facts.&lt;/strong&gt; My life shows my own photos, each one marked up with where and when it was taken, and listed in the image sitemap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A named author.&lt;/strong&gt; Every post is a &lt;code&gt;BlogPosting&lt;/code&gt; by that same person, with an author box under it, and every outside fact has a dated source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A footer that does the work.&lt;/strong&gt; Every page links to the projects, the CV, the blog, its RSS feed and my profiles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One address per page.&lt;/strong&gt; One canonical URL, the language versions linked to each other, and a share card for every page in every language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The build fails if a page loses its title, description or canonical, or if the structured data stops parsing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzalc54n5i9agahzkqe8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzalc54n5i9agahzkqe8.webp" alt="The author box under a post: my avatar, my name, a one-line bio and links to More about me, the CV and Contact" width="673" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author box&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyhbo36ix1tz63b98j3yu.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyhbo36ix1tz63b98j3yu.webp" alt="The site footer: columns for Work, Site with Blog, CV, My life and RSS, Elsewhere with my profiles, the legal pages and a Pause motion button" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Footer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The author box under every post and the footer on every page: the same person, the same links, everywhere.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How is every change checked?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Static.&lt;/strong&gt; Types, lint and unit tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browsers.&lt;/strong&gt; Playwright on every page, with axe for accessibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eyes.&lt;/strong&gt; Screenshots at phone, tablet and desktop widths that I look at myself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed.&lt;/strong&gt; Lighthouse on a slow phone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;↻ Anything that fails becomes a fix, and a repeated mistake becomes a lesson in the wiki.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nothing is done until the checks pass and I've looked at the screenshots myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is it built with?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Astro 7 (&lt;a href="https://muszarski.com/en/blog/astro-vs-nextjs-for-a-portfolio/" rel="noopener noreferrer"&gt;why not Next.js&lt;/a&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language and styling&lt;/td&gt;
&lt;td&gt;TypeScript, Tailwind CSS 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Translations&lt;/td&gt;
&lt;td&gt;Lingui&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repo&lt;/td&gt;
&lt;td&gt;Turborepo and bun&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Font&lt;/td&gt;
&lt;td&gt;Anybody, a variable font (OFL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Icons&lt;/td&gt;
&lt;td&gt;Tabler (MIT) and Simple Icons (CC0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contact form&lt;/td&gt;
&lt;td&gt;EmailJS behind a Vercel function, Cloudflare Turnstile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Analytics&lt;/td&gt;
&lt;td&gt;Umami Cloud, cookieless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;Playwright, axe-core, Vitest, Lighthouse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI&lt;/td&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where did it end up?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokdfev9ts7fcrh63n8oz.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fokdfev9ts7fcrh63n8oz.webp" alt="A Lighthouse report for the home page on mobile: four green gauges for Performance, Accessibility, Best Practices and SEO" width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The home page in Lighthouse on mobile, from a local production build on 7 October 2026. Lab numbers: real-user data comes after launch.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you'd like to talk about building something like this, or about a role, &lt;a href="https://muszarski.com/en/#contact" rel="noopener noreferrer"&gt;my contact form is one message long&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;How this post was made: I wrote it with Claude Code. It drafted the text from my project's wiki, code and notes; I set the direction, and reviewed and approved it before it went out.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f" rel="noopener noreferrer"&gt;llm-wiki.md, Andrej Karpathy's idea file (GitHub Gist, 4 April 2026)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.chrome.com/docs/lighthouse/performance/performance-scoring" rel="noopener noreferrer"&gt;Lighthouse performance scoring (Chrome for Developers)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html" rel="noopener noreferrer"&gt;Understanding Success Criterion 2.2.2: Pause, Stop, Hide (W3C)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.awwwards.com/websites/" rel="noopener noreferrer"&gt;Awwwards, Sites of the Day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mobbin.com/" rel="noopener noreferrer"&gt;Mobbin, a library of real app and web screens&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dequelabs/axe-core" rel="noopener noreferrer"&gt;axe-core, accessibility rules engine (Deque)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.solarsystemscope.com/textures/" rel="noopener noreferrer"&gt;Solar System Scope, planet textures (CC BY 4.0), used in the old space portfolio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fonts.google.com/specimen/Anybody" rel="noopener noreferrer"&gt;Anybody, a variable font (Google Fonts)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>astro</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
