Skip to content
← writing

Building a pixel-dissolve marquee

css
backdrop-filter
pixelation
frontend

Every logo marquee on the internet fades its edges the same way: a linear-gradient mask that ramps opacity to zero. It's fine. It's also everywhere. I wanted the edge to actually feel like something, so I made the content disintegrate into pixels instead.

Orbit
Prism
Vertex
Loop
Quanta
Flux
Cobalt
Ember

One ramp isn't enough

A gradient fade changes exactly one thing across the edge: opacity. The result is soft, but it's flat. The content just gets quieter. Real disintegration changes a few things at once. As a logo travels toward the edge it should get chunkier, blurrier, and fainter, all together.

So instead of a single mask, I overlay a stack of vertical bands on each edge. Each band is a plain absolutely-positioned div, and the further out it sits, the harder it dissolves whatever's behind it.

Three ramps, one band

For each band I compute its outwardness t (1 at the outermost slice, trending to 0 at the solid interior) and drive three properties off it.

const t = 1 - (k + 0.5) / bands; // 1 (outer) → 0 (inner)
 
const blur = t * maxBlur;                  // backdrop blur grows
const pixel = base * 2 ** Math.floor(t * 4); // pixel blocks grow
const fadePct = Math.pow(t, 1.35) * 96;    // fades into the surface

The pow(t, 1.35) curve on the fade keeps the inner bands nearly solid and makes the falloff bite right at the edge, so content stays legible until it's genuinely on its way out.

Where the "pixels" come from

The blocky look is cheap. Each band paints a 1px mortar grid over its blurred backdrop, and the grid cell size is the band's pixel value.

band.style.backdropFilter = `blur(${blur}px)`;
band.style.backgroundColor =
  `color-mix(in srgb, ${surface} ${fadePct}%, transparent)`;
band.style.backgroundImage =
  `linear-gradient(${line} 1px, transparent 1px),
   linear-gradient(90deg, ${line} 1px, transparent 1px)`;
band.style.backgroundSize = `${pixel}px ${pixel}px`;

backdrop-filter blurs whatever's scrolling behind the band, and the grid chops that blur into cells. Since each band has its own cell size, the blocks visibly grow as you move outward: small near the content, coarse at the edge. color-mix handles the fade without needing the surface color pre-split into an rgba.

Keeping the grid seamless

The trap with stacked bands is the lattice jumping phase between zones, which reads as broken squares or stray lines. Two invariants fix it. Each band's column width is a whole multiple of the largest cell, and the pixel sizes are a doubling sequence (base, 2·base, 4·base, and so on). So a coarse band's grid lines always land exactly on the finer band's lattice, and the squares stay square all the way out.

The thing I'd carry to other effects: a convincing dissolve ramps several properties together, not just opacity. The mortar-grid-over-backdrop-filter trick fakes pixelation with no per-frame work, the bands compute once with useMemo, and passing the real surface color is what lets the edges melt into the actual backdrop instead of a guess.

The full, prop-driven component lives on the Pixelated Marquee page. Drag the sliders to feel how pixelSize, maxBlur, and edgeWidth change the dissolve.

Ask your agent to implement this

Read the full writeup at https://seangeng.com/writing/building-a-pixel-dissolve-marquee.md and implement it in my project.

It covers: Building a pixel-dissolve marquee. Why I replaced the soft gradient fade on a logo marquee with edges that disintegrate into graduated pixel blocks: bigger, blurrier, and fainter the further out they go.

Requirements:
- Follow the technique/approach exactly as described in the writeup.
- Adapt names, colors, and styling to my project's existing conventions.
- If it's a component, make it reusable with sensible props and TypeScript types.
- Keep it accessible: semantic HTML, keyboard support, and respect prefers-reduced-motion.
- When done, tell me which files you created or changed and how to use it.

Paste into Claude Code, Codex, Cursor, or any agent. view raw .md download source .zip