A Design Pass with DeepSeek V4.1 FlashUsing the free DeepSeek V4.1 Flash model for a design and performance pass: glass surfaces, consent-aware analytics, a server-rendered cookie banner, and a faster first paint

2026-10-207 min read
AI
Frontend
Performance

A Design Pass with DeepSeek V4.1 Flash

tl;dr:

DeepSeek V4.1 Flash is available as a free model inside OpenCode. I used it for a focused design and performance pass: background geometry, a glass timeline, a theme-aware logo, consent-aware analytics, a server-rendered cookie banner, a faster first paint, and responsive diagrams.

DeepSeek released V4.1 Flash in September 2026: a 552B-parameter mixture-of-experts model with 8B active parameters for input, 16B for output, a one-million-token context window, and native image understanding.

I did not need most of that. I needed a model that could read a small Preact codebase, follow conventions, make a controlled CSS change, and help update tests. V4.1 Flash was fast enough to keep that loop tight, and free inside OpenCode, which made a long visual review easy without another subscription.

This post is about what it changed, and where human review still mattered.

The brief

The site already had a clear visual language: warm backgrounds, glass surfaces, sharp typography, and strong black and white states for active controls. This was not a redesign. It was a list of small inconsistencies:

  • The background gradients left a visible edge near the bottom of the page.
  • The logo did not adapt cleanly between light and dark themes.
  • The cookie banner appeared too late and was too transparent.
  • The blog filters used native selects while the rest of the site used pill-shaped links.
  • The blog diagrams were hard to read on a phone.

Each item sounded isolated, but together they asked one question: does a small change respect the rest of the system?

That is where a model helps: it can search, compare, and patch quickly. It cannot decide whether the result feels right.

Five surface issues lead to one system check; the model searches and patches, the human inspects and decides.

Surface work

The background used large circular gradients sized in viewport units, so the bottom one was clipped in some viewports. Fixed-size ellipses and a bottom gradient pushed past the viewport kept the wash without the hard cut. The model found the geometry; I checked both themes.

The timeline took longer. The first version used a translucent background with backdrop-filter. It looked acceptable in isolation, but the mask that faded the line interfered with the blur in Chromium. The browser could not reliably paint the backdrop through the masked element, so the result changed with the content underneath.

The fix was to stop treating the line as blurred glass and build it from layered gradients: a vertical tint, horizontal specular edges, and a mask that fades into the page. The line is seven pixels wide, with a separate dark-mode gradient set, and stays out of the accessibility tree.

The logo is an inline SVG, so the model updated the fills without shipping a second file. Light mode uses a dark rounded square with white letters; dark mode inverts them. Hover, focus, and pressed states stayed part of the theme system instead of being hardcoded for one mode.

The model proposed the layered timeline; it did not decide it looked like glass. That came from looking at it in the browser, at different sizes and against different backgrounds.

Consent and first paint

The analytics change started as a behavioral fix. The site uses GA4, but tracking should not start until the visitor grants consent. The model wired the consent state into the loader, removed the old interaction fallback, and covered the behavior with unit tests.

The second pass moved the banner earlier in the page lifecycle. It used to mount after hydration, so a first-time visitor saw it late and a returning visitor could see a flash before it was removed. The banner is now part of the server-rendered HTML. An inline head script reads the stored consent and adds a cookie-consent-set class before the first paint. CSS hides the banner when that class is present; after hydration, the component removes it from the DOM.

A first-time visitor gets the prompt in the initial HTML. A returning visitor gets the same HTML, but the banner is hidden before it can paint. The boot loader sits above the consent bar on slow loads, so the buttons never look ready before the app is. When scripts are unavailable or fail, both stay out of the way.

First-time and returning visitors share the same server HTML; stored consent hides the banner before first paint.

The browser cannot prove a privacy contract by rendering the page; tests can.

The first paint needed its own pass. The hero image now ships a 240px JPEG for 1x and a 400px WebP for 2x, and loads eagerly with fetchpriority="high". The header illustration has mobile and desktop sources.

The hero used to wait for hydration. The heading, portrait, and description now animate from the first frame via forceVisible; reduced motion and the animation preference still apply.

The boot loader waits 300ms, so fast loads never flash a spinner. If hydration is slow it shows a status message; if the module fails, the load event removes it. No-JS and error states hide it.

Lighthouse flagged the 13 KiB stylesheet as render-blocking, but the audit was unscored and estimated 0ms. Inlining it removed the request and worsened FCP/LCP: the HTML grew from roughly 10 KiB to 25 KiB compressed. I reverted it.

The more interesting metric was LCP. When the portrait starts at opacity: 0, Chrome does not count it as contentful paint. The largest element became the cookie prompt instead. Server-rendering the prompt moved it into the initial paint. LCP is a paint timeline, not a design review.

Blog, diagrams, and motion

The blog had two navigation patterns disconnected from the drawer menu: native selects for the tag filter and sort control, and a mix of text pills and small page buttons for pagination. They now share link pills, a two-pill sort group, and a quiet glass rail. The active state is shared with the side drawer.

The change also fixed a state bug: changing a filter while on page two could leave the visitor on a page that no longer existed. Filter and sort links now reset to the first page.

The links are real links. They keep href values, preserve the language prefix, and still support new-tab and middle-click navigation. Filtering itself runs after hydration, so a <button> with an onClick handler would remove the remaining link behavior. The existing pagination already used links, so the model had a good pattern to follow.

The old diagrams used wide compositions and small labels, which were close to useless on a phone. Each diagram now has a desktop and mobile file. The mobile version uses a narrower canvas, stacks the panels, and increases the type size. The MDX picks the asset with a <picture> element, so there is no JavaScript, no layout shift, and no extra request on desktop.

The header animates inside the SVG with a moving packet; the new diagrams stay static so their labels remain readable. The files still read when motion is removed, and the header animation respects prefers-reduced-motion.

The budget

The design pass also became a lesson in where effects belong. backdrop-filter is no longer a default surface. Blur is limited to the header, overlays, and the cookie banner. Other panels use layered translucent backgrounds instead, and the header uses a smaller blur on small screens.

The background used background-attachment: fixed, which forces a repaint while scrolling. It now lives on a fixed pseudo-element behind the page. The dark theme received a darker base and lower opacity washes, keeping depth without a light gray canvas.

The animated SVG headers used feGaussianBlur; a filter rasterizes every frame while the SVG animates. The glow is now a wider, low-opacity rect behind the sharp line. Below-the-fold sections use content-visibility: auto, and the closed side drawer no longer keeps will-change alive.

I did not measure a dramatic Lighthouse jump. The goal was to remove work the browser should not have been doing on every scroll or animation frame. The effects now have a budget instead of being spread across every surface.

Blur stays on three surfaces, repaint moves to a fixed layer, and offscreen sections skip work.

What the model did not do

DeepSeek V4.1 Flash did not decide that the first glass timeline looked wrong. It did not notice that a filter change should reset pagination. It did not choose the dark-mode contrast of the active pill or know which labels to drop from a mobile diagram. It did not decide that inlining a stylesheet was a bad trade or that a server-rendered consent banner was the right fix for a late LCP element.

It also did not update the visual snapshots by itself in a trustworthy way. The test suite can tell you that HTML changed. It cannot tell you that the new HTML is better. I reviewed the diff and ran the production build before accepting it.

The loop was consistent: I defined the constraint, the model searched and patched, I inspected the result, the tests caught regressions, and I decided what shipped. It is faster with a capable free model. It is not automatic.

The result

The site still has the same architecture: Preact, TypeScript, Vite, Tailwind, MDX, static rendering, and a small amount of client-side hydration. The design pass changed the surface; the follow-up changed when the surface becomes visible.

The blog now has responsive diagrams, shared navigation, and a prose width that is easier to read on large screens. The consent banner is part of the first paint, and the hero no longer waits for JavaScript. The checks are intentionally boring: typecheck, lint, format, unit tests, production build, and Playwright against the built output.

That is the version of AI-assisted development I want to keep using. Fast feedback, small diffs, real constraints, and a human who still has to look at the page.

This pass is still a work in progress. The diagrams, layout, and copy will keep changing, and this post can be updated whenever they do.

🏁 Thanks for reading! If you have questions or feedback, feel free to reach out.

Site powered by

paulogoncalves.dev ©️ 2021 - 2026 — MIT

Loading content...