Uma passagem de design com DeepSeek V4.1 FlashUsar o modelo gratuito DeepSeek V4.1 Flash para uma passagem de design e performance: superfícies de vidro, analytics com consentimento, banner de cookies renderizado no servidor e um primeiro render mais rápido
A Design Pass with DeepSeek V4.1 Flash
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.
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.
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.
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.
🏁 Obrigado por ler! Se tiver alguma questão ou feedback, não hesite em contactar.