PSX Wobble

Glitch & Distortion · Animated · pure CSS

Per-letter transforms snap between procedurally generated integer-pixel positions on a stepped timing function, the classic PS1 fixed-point vertex jitter. A muddy, hard-banded gradient fills the glyphs and swims independently underneath on its own stepped loop, so the texture visibly slides beneath the snapping outlines.

PSX Wobble

How it works

PSX Wobble is an animated glitch & distortion text effect rendered entirely in CSS. Each character is wrapped in its own span so it can animate independently — the HTML and JSX exports include that per-letter markup.

Controls

PSX Wobble exposes 5 dedicated controls — Steps, Wobble, Jitter Speed, Swim Speed and Palette Hue — on top of the shared type controls (font, weight, letter-spacing and case). Open it in the generator to tune every value live, then copy the updated CSS.

CSS

/* PSX Wobble — made with TEXT-FX · https://text-fx.app
 * HTML: each character is wrapped in a <span> — see the HTML export.
 * Font: 'Syne', sans-serif (load from Google Fonts).
 */

.text-effect {
  font-family: 'Syne', sans-serif;
  font-weight: 700;
  letter-spacing: 8px;
  text-transform: none;
}

.text-effect {
  display: inline-block;
  white-space: pre;
  transform: skewX(-6deg);
}
.text-effect .fx-ch {
  display: inline-block;
  background: repeating-linear-gradient(68deg, hsl(171 34% 22%) 0%, hsl(171 34% 22%) 10%, hsl(61 30% 36%) 10%, hsl(61 30% 36%) 26%, hsl(44 38% 56%) 26%, hsl(44 38% 56%) 40%, hsl(48 46% 78%) 40%, hsl(48 46% 78%) 52%, hsl(32 34% 38%) 52%, hsl(32 34% 38%) 70%, hsl(171 34% 22%) 70%, hsl(171 34% 22%) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  background-size: 220% 260%;
  filter: drop-shadow(1.5px 1.5px 0 hsl(140 25% 5%)) drop-shadow(-1px 0 0 hsl(140 25% 5%));
  animation:
    text-effect-jitter 1.70s steps(1, jump-end) infinite,
    text-effect-swim 0.60s steps(1, jump-end) infinite;
  animation-delay:
    calc(var(--i) * -0.1889s),
    calc(var(--i) * -0.126s);
}

@keyframes text-effect-jitter {
  0% { transform: translate(2px, 0px) skewX(0deg); }
  11.11% { transform: translate(-1px, -2px) skewX(0deg); }
  22.22% { transform: translate(-1px, 0px) skewX(1deg); }
  33.33% { transform: translate(-1px, 0px) skewX(0deg); }
  44.44% { transform: translate(-1px, 2px) skewX(1deg); }
  55.56% { transform: translate(0px, -2px) skewX(-1deg); }
  66.67% { transform: translate(2px, 1px) skewX(-1deg); }
  77.78% { transform: translate(0px, 0px) skewX(-1deg); }
  88.89% { transform: translate(0px, -1px) skewX(2deg); }
  100% { transform: translate(2px, 0px) skewX(0deg); }
}
@keyframes text-effect-swim {
  0% { background-position: 93.3% 64%; }
  11.11% { background-position: 76.8% 28%; }
  22.22% { background-position: 38.2% 93.4%; }
  33.33% { background-position: 64% 10.7%; }
  44.44% { background-position: 8.2% 85.5%; }
  55.56% { background-position: 71.8% 62.4%; }
  66.67% { background-position: 88.4% 7.8%; }
  77.78% { background-position: 47.6% 97.5%; }
  88.89% { background-position: 95.1% 22.2%; }
  100% { background-position: 93.3% 64%; }
}

HTML

This effect needs the markup below (per-letter spans, SVG defs, or a data-text attribute).

<!-- Made with TEXT-FX · https://text-fx.app -->

<style>
.text-effect {
  font-family: 'Syne', sans-serif;
  font-weight: 700;
  letter-spacing: 8px;
  text-transform: none;
}

.text-effect {
  display: inline-block;
  white-space: pre;
  transform: skewX(-6deg);
}
.text-effect .fx-ch {
  display: inline-block;
  background: repeating-linear-gradient(68deg, hsl(171 34% 22%) 0%, hsl(171 34% 22%) 10%, hsl(61 30% 36%) 10%, hsl(61 30% 36%) 26%, hsl(44 38% 56%) 26%, hsl(44 38% 56%) 40%, hsl(48 46% 78%) 40%, hsl(48 46% 78%) 52%, hsl(32 34% 38%) 52%, hsl(32 34% 38%) 70%, hsl(171 34% 22%) 70%, hsl(171 34% 22%) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  background-size: 220% 260%;
  filter: drop-shadow(1.5px 1.5px 0 hsl(140 25% 5%)) drop-shadow(-1px 0 0 hsl(140 25% 5%));
  animation:
    text-effect-jitter 1.70s steps(1, jump-end) infinite,
    text-effect-swim 0.60s steps(1, jump-end) infinite;
  animation-delay:
    calc(var(--i) * -0.1889s),
    calc(var(--i) * -0.126s);
}

@keyframes text-effect-jitter {
  0% { transform: translate(2px, 0px) skewX(0deg); }
  11.11% { transform: translate(-1px, -2px) skewX(0deg); }
  22.22% { transform: translate(-1px, 0px) skewX(1deg); }
  33.33% { transform: translate(-1px, 0px) skewX(0deg); }
  44.44% { transform: translate(-1px, 2px) skewX(1deg); }
  55.56% { transform: translate(0px, -2px) skewX(-1deg); }
  66.67% { transform: translate(2px, 1px) skewX(-1deg); }
  77.78% { transform: translate(0px, 0px) skewX(-1deg); }
  88.89% { transform: translate(0px, -1px) skewX(2deg); }
  100% { transform: translate(2px, 0px) skewX(0deg); }
}
@keyframes text-effect-swim {
  0% { background-position: 93.3% 64%; }
  11.11% { background-position: 76.8% 28%; }
  22.22% { background-position: 38.2% 93.4%; }
  33.33% { background-position: 64% 10.7%; }
  44.44% { background-position: 8.2% 85.5%; }
  55.56% { background-position: 71.8% 62.4%; }
  66.67% { background-position: 88.4% 7.8%; }
  77.78% { background-position: 47.6% 97.5%; }
  88.89% { background-position: 95.1% 22.2%; }
  100% { background-position: 93.3% 64%; }
}
</style>

<div class="text-effect"><span class="fx-ch" style="--i:0;--n:9;--rev:8;--mid:4">Y</span><span class="fx-ch" style="--i:1;--n:9;--rev:7;--mid:4">o</span><span class="fx-ch" style="--i:2;--n:9;--rev:6;--mid:4">u</span><span class="fx-ch" style="--i:3;--n:9;--rev:5;--mid:4">r</span><span class="fx-ch" style="--i:4;--n:9;--rev:4;--mid:4"> </span><span class="fx-ch" style="--i:5;--n:9;--rev:3;--mid:4">t</span><span class="fx-ch" style="--i:6;--n:9;--rev:2;--mid:4">e</span><span class="fx-ch" style="--i:7;--n:9;--rev:1;--mid:4">x</span><span class="fx-ch" style="--i:8;--n:9;--rev:0;--mid:4">t</span></div>
Category
Glitch & Distortion
Type
Animated
Browser support
background-clip:text gradient + stepped transform (all modern, -webkit- prefixed)
Capabilities
perLetter

Related Glitch & Distortion effects