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.
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
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 growsconst pixel = base * 2 ** Math.floor(t * 4); // pixel blocks growconst 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.
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.