Glitch Art is a digital aesthetic rooted in the deliberate exploitation of technological errors, data corruption, and signal malfunction to produce visually striking compositions. Emerging from net art and new media art communities in the mid-2000s – with theoretical grounding established by Rosa Menkman’s Glitch Studies Manifesto (2010) and The Glitch Moment(um) (2011) – it celebrates the beauty found in broken data, pixel sorting, datamoshing, and RGB channel separation. Predecessors include early video feedback experiments and data-bent photography, but the movement crystallized as a distinct genre around 2006-2009, accelerated by social sharing and DIY datamoshing tutorials. In web and UI design, Glitch Art translates to RGB split text effects, scan line overlays, noise grain textures, corrupted grid layouts, distorted imagery, and animations that simulate signal interference. The core philosophy treats the glitch not as failure but as revelation – exposing the hidden mechanics of digital systems and challenging the assumption that technology should always appear seamless and polished.
Glitch Art palettes draw from the RGB color model itself – the raw channels of digital displays – combined with neon accents that evoke CRT phosphors, VHS artifacts, and corrupted data streams. Deep black backgrounds maximize the luminosity of channel-split colors.
| Color Name | Hex | Role / Usage |
|---|---|---|
| Void Black | #0D0D0D |
Primary background, deepest canvas surface |
| Screen Dark | #1A1A2E |
Secondary background, dark panels with subtle blue cast |
| Static Gray | #2A2A2A |
Tertiary surfaces, noise texture base |
| Channel Red | #FF0040 |
RGB red channel, primary split offset color |
| Channel Green | #00FF41 |
RGB green channel, terminal/matrix accent |
| Channel Blue | #0080FF |
RGB blue channel, secondary split offset color |
| Glitch Cyan | #00FFFF |
High-energy accent, scan line tint, hyperlinks |
| Glitch Magenta | #FF00FF |
High-energy accent, chromatic aberration highlight |
| Corrupt Pink | #FF2E97 |
Hot accent for buttons, alert states, key UI elements |
| Signal Yellow | #F5F500 |
Warning accents, data highlight, hover state feedback |
| Data White | #E0E0E0 |
Primary text, readable body content |
| Phosphor White | #FFFFFF |
Display headings, maximum-contrast elements |
| Artifact Purple | #7B2FBE |
Decorative gradients, secondary data visualization |
| Noise Mid | #444444 |
Muted borders, disabled states, subtle separators |
| Codec Orange | #FF6B2B |
Tertiary accent, compression artifact visualization |
:root {
/* Backgrounds */
--glitch-void: #0d0d0d;
--glitch-screen-dark: #1a1a2e;
--glitch-static-gray: #2a2a2a;
/* RGB Channels */
--glitch-red: #ff0040;
--glitch-green: #00ff41;
--glitch-blue: #0080ff;
/* Neon Accents */
--glitch-cyan: #00ffff;
--glitch-magenta: #ff00ff;
--glitch-pink: #ff2e97;
--glitch-yellow: #f5f500;
--glitch-purple: #7b2fbe;
--glitch-orange: #ff6b2b;
/* Neutrals */
--glitch-white: #ffffff;
--glitch-text: #e0e0e0;
--glitch-muted: #444444;
/* Functional Tokens */
--glitch-bg: var(--glitch-void);
--glitch-surface: var(--glitch-screen-dark);
--glitch-border: var(--glitch-muted);
--glitch-accent: var(--glitch-cyan);
--glitch-accent-alt: var(--glitch-pink);
--glitch-link: var(--glitch-cyan);
--glitch-link-hover: var(--glitch-magenta);
}
Glitch Art typography favors monospaced, technical, and geometric typefaces that reference code editors, terminal displays, and early computing. Display text is often treated as a surface for corruption effects – split, distorted, and layered – while body text prioritizes legibility against noisy backgrounds.
| Font | Weight(s) | Usage | Link |
|---|---|---|---|
| Share Tech Mono | 400 | Body text, data displays, code-like content | fonts.google.com/specimen/Share+Tech+Mono |
| VT323 | 400 | Display text, retro terminal headings, pixel-style accents | fonts.google.com/specimen/VT323 |
| Space Mono | 400, 700 | Body text, UI labels, technical content | fonts.google.com/specimen/Space+Mono |
| Orbitron | 400, 500, 700, 900 | Headlines, display text, futuristic titles | fonts.google.com/specimen/Orbitron |
| IBM Plex Mono | 400, 500, 700 | Body text, metadata, system-inspired interfaces | fonts.google.com/specimen/IBM+Plex+Mono |
| Press Start 2P | 400 | Pixel-art accents, retro labels, 8-bit references | fonts.google.com/specimen/Press+Start+2P |
| Major Mono Display | 400 | Display headlines, abstract title treatments | fonts.google.com/specimen/Major+Mono+Display |
| Russo One | 400 | Bold geometric headlines, impactful display text | fonts.google.com/specimen/Russo+One |
| Heading | Body | Vibe |
|---|---|---|
| Orbitron (700) | Share Tech Mono | Futuristic authority meets clean terminal readability; ideal for tech-forward glitch layouts |
| Russo One | IBM Plex Mono | Bold geometric impact paired with professional monospace; balances chaos with legibility |
| VT323 | Space Mono | Retro pixel nostalgia meets modern monospace precision; perfect for CRT-inspired interfaces |
| Major Mono Display | Share Tech Mono | Abstract, deconstructed headlines with grounded technical body text; maximizes the digital-error feel |
| Orbitron (900) | IBM Plex Mono (400) | Heavy futuristic display with readable IBM technical prose; suitable for data-driven glitch dashboards |
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&family=VT323&display=swap');
/* === Base Typography === */
body {
font-family: 'Share Tech Mono', 'Courier New', Courier, monospace;
font-size: 16px;
line-height: 1.7;
color: var(--glitch-text);
background-color: var(--glitch-bg);
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Orbitron', 'Arial Black', sans-serif;
text-transform: uppercase;
letter-spacing: 0.08em;
line-height: 1.1;
color: var(--glitch-white);
margin: 0 0 0.5em 0;
}
h1 {
font-size: clamp(2.5rem, 7vw, 6rem);
font-weight: 900;
}
h2 {
font-size: clamp(1.8rem, 4vw, 3rem);
font-weight: 700;
}
h3 {
font-size: clamp(1.2rem, 2.5vw, 1.8rem);
font-weight: 700;
}
a {
color: var(--glitch-link);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: color 0.15s ease, border-color 0.15s ease;
}
a:hover {
color: var(--glitch-link-hover);
border-bottom-color: var(--glitch-link-hover);
}
code, pre {
font-family: 'Share Tech Mono', 'Courier New', monospace;
background-color: var(--glitch-static-gray);
border: 1px solid var(--glitch-muted);
padding: 0.2em 0.5em;
color: var(--glitch-green);
}
pre {
padding: 1.25em;
overflow-x: auto;
white-space: pre;
border-left: 3px solid var(--glitch-cyan);
}
::selection {
background-color: var(--glitch-magenta);
color: var(--glitch-white);
}
min-height: 100vh to create distinct scene-like moments as the user scrolls through the corrupted landscapeA content card with scan line overlay, subtle RGB offset on hover, and a corrupted-data border treatment.
.glitch-card {
position: relative;
background-color: var(--glitch-surface);
border: 1px solid var(--glitch-muted);
padding: 2rem;
overflow: hidden;
transition: transform 0.2s ease, border-color 0.3s ease;
}
/* Scan line overlay */
.glitch-card::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.15) 2px,
rgba(0, 0, 0, 0.15) 4px
);
pointer-events: none;
z-index: 1;
}
.glitch-card:hover {
border-color: var(--glitch-cyan);
transform: translate(-2px, -1px);
box-shadow:
2px 0 0 var(--glitch-red),
-2px 0 0 var(--glitch-blue);
}
.glitch-card h3 {
position: relative;
z-index: 2;
font-family: 'Orbitron', sans-serif;
font-size: 1.1rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--glitch-cyan);
margin-bottom: 0.75rem;
}
.glitch-card p {
position: relative;
z-index: 2;
font-size: 0.9rem;
line-height: 1.6;
color: var(--glitch-text);
}
.glitch-card .tag {
display: inline-block;
position: relative;
z-index: 2;
font-family: 'Share Tech Mono', monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.12em;
padding: 0.25rem 0.6rem;
border: 1px solid var(--glitch-muted);
color: var(--glitch-green);
margin-right: 0.25rem;
margin-top: 0.75rem;
}
A button with animated RGB split on hover, using pseudo-elements to create the chromatic aberration effect.
.glitch-btn {
position: relative;
display: inline-block;
font-family: 'Orbitron', sans-serif;
font-size: 0.85rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.15em;
padding: 0.9rem 2rem;
border: 1px solid var(--glitch-cyan);
background-color: transparent;
color: var(--glitch-cyan);
cursor: pointer;
text-decoration: none;
overflow: hidden;
transition: background-color 0.2s ease, color 0.2s ease;
}
.glitch-btn::before,
.glitch-btn::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 0.9rem 2rem;
opacity: 0;
pointer-events: none;
}
.glitch-btn::before {
color: var(--glitch-red);
z-index: -1;
}
.glitch-btn::after {
color: var(--glitch-blue);
z-index: -1;
}
.glitch-btn:hover {
background-color: var(--glitch-cyan);
color: var(--glitch-void);
animation: btn-glitch 0.3s ease forwards;
}
.glitch-btn:hover::before {
opacity: 0.7;
animation: rgb-shift-left 0.4s infinite;
}
.glitch-btn:hover::after {
opacity: 0.7;
animation: rgb-shift-right 0.4s infinite;
}
@keyframes btn-glitch {
0% { transform: translate(0); }
20% { transform: translate(-3px, 2px); }
40% { transform: translate(2px, -1px); }
60% { transform: translate(-1px, 1px); }
80% { transform: translate(1px, -2px); }
100% { transform: translate(0); }
}
@keyframes rgb-shift-left {
0%, 100% { transform: translate(-2px, 0); }
50% { transform: translate(-4px, 1px); }
}
@keyframes rgb-shift-right {
0%, 100% { transform: translate(2px, 0); }
50% { transform: translate(4px, -1px); }
}
A top navigation with a subtle interference band and scan line texture, featuring glitch-styled hover states.
.glitch-nav {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 2rem;
background-color: var(--glitch-void);
border-bottom: 1px solid var(--glitch-muted);
z-index: 100;
}
/* Bottom interference line */
.glitch-nav::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(
90deg,
var(--glitch-cyan) 0%,
var(--glitch-magenta) 33%,
var(--glitch-green) 66%,
var(--glitch-cyan) 100%
);
background-size: 200% 100%;
animation: interference-scan 3s linear infinite;
}
@keyframes interference-scan {
0% { background-position: 0% 0%; }
100% { background-position: 200% 0%; }
}
.glitch-nav .logo {
font-family: 'Orbitron', sans-serif;
font-size: 1.1rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.2em;
color: var(--glitch-white);
text-decoration: none;
}
.glitch-nav ul {
list-style: none;
display: flex;
gap: 0;
margin: 0;
padding: 0;
}
.glitch-nav a {
display: block;
padding: 0.5rem 1.25rem;
font-family: 'Share Tech Mono', monospace;
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--glitch-text);
text-decoration: none;
border: none;
position: relative;
transition: color 0.15s ease;
}
.glitch-nav a:hover {
color: var(--glitch-cyan);
text-shadow:
2px 0 var(--glitch-red),
-2px 0 var(--glitch-blue);
}
.glitch-nav a::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 1px;
background-color: var(--glitch-cyan);
transition: width 0.2s ease, left 0.2s ease;
}
.glitch-nav a:hover::after {
width: 100%;
left: 0;
}
A full-viewport hero with animated RGB-split headline text, scan line overlay, and noise texture background.
.glitch-hero {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
padding: 4rem 3rem;
background-color: var(--glitch-void);
overflow: hidden;
}
/* Noise texture layer */
.glitch-hero::before {
content: '';
position: absolute;
inset: -50%;
width: 200%;
height: 200%;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.04'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 1;
}
/* Scan line overlay */
.glitch-hero::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 0, 0, 0.12) 2px,
rgba(0, 0, 0, 0.12) 4px
);
pointer-events: none;
z-index: 2;
}
.glitch-hero__content {
position: relative;
z-index: 3;
max-width: 900px;
}
.glitch-hero__title {
font-family: 'Orbitron', sans-serif;
font-size: clamp(3rem, 9vw, 8rem);
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.05em;
line-height: 0.95;
color: var(--glitch-white);
position: relative;
}
.glitch-hero__subtitle {
font-family: 'Share Tech Mono', monospace;
font-size: clamp(0.9rem, 1.5vw, 1.2rem);
color: var(--glitch-text);
max-width: 50ch;
margin-top: 1.5rem;
line-height: 1.7;
}
.glitch-hero__actions {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 2.5rem;
}
An animated chromatic aberration effect on text using pseudo-elements, where red and blue copies of the text are offset and blended to create the signature glitch look.
.rgb-split {
position: relative;
display: inline-block;
color: var(--glitch-white);
font-family: 'Orbitron', sans-serif;
font-weight: 900;
text-transform: uppercase;
}
.rgb-split::before,
.rgb-split::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.rgb-split::before {
color: var(--glitch-red);
mix-blend-mode: screen;
animation: rgb-split-red 3s infinite;
clip-path: inset(0 0 0 0);
}
.rgb-split::after {
color: var(--glitch-blue);
mix-blend-mode: screen;
animation: rgb-split-blue 3s infinite;
clip-path: inset(0 0 0 0);
}
@keyframes rgb-split-red {
0%, 100% { transform: translate(-2px, 0); }
25% { transform: translate(2px, 1px); clip-path: inset(30% 0 40% 0); }
50% { transform: translate(-1px, -1px); clip-path: inset(0 0 0 0); }
75% { transform: translate(3px, 0); clip-path: inset(60% 0 10% 0); }
}
@keyframes rgb-split-blue {
0%, 100% { transform: translate(2px, 0); }
25% { transform: translate(-3px, -1px); clip-path: inset(50% 0 20% 0); }
50% { transform: translate(1px, 1px); clip-path: inset(0 0 0 0); }
75% { transform: translate(-2px, 0); clip-path: inset(10% 0 70% 0); }
}
/* Reduced motion variant */
@media (prefers-reduced-motion: reduce) {
.rgb-split::before {
animation: none;
transform: translate(-2px, 0);
}
.rgb-split::after {
animation: none;
transform: translate(2px, 0);
}
}
A reusable overlay component that applies CRT-style scan lines to any container, with optional animated flicker.
.scanlines {
position: relative;
overflow: hidden;
}
.scanlines::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 2px,
rgba(0, 0, 0, 0.2) 2px,
rgba(0, 0, 0, 0.2) 4px
);
pointer-events: none;
z-index: 10;
}
/* Animated variant with vertical scan bar */
.scanlines--animated::before {
content: '';
position: absolute;
top: -100%;
left: 0;
width: 100%;
height: 30%;
background: linear-gradient(
180deg,
transparent 0%,
rgba(0, 255, 255, 0.03) 50%,
transparent 100%
);
pointer-events: none;
z-index: 11;
animation: scan-sweep 4s linear infinite;
}
@keyframes scan-sweep {
0% { top: -30%; }
100% { top: 130%; }
}
/* CRT screen curvature (optional enhancement) */
.scanlines--crt {
border-radius: 12px;
box-shadow:
inset 0 0 60px rgba(0, 0, 0, 0.4),
inset 0 0 10px rgba(0, 0, 0, 0.3);
}
@media (prefers-reduced-motion: reduce) {
.scanlines--animated::before {
animation: none;
display: none;
}
}
A CSS treatment that simulates datamoshing on images using blend modes, clip-path slicing, and color channel manipulation.
.datamosh {
position: relative;
overflow: hidden;
display: block;
}
.datamosh img {
display: block;
width: 100%;
height: auto;
filter: contrast(1.1) saturate(1.3);
}
/* Red channel ghost */
.datamosh::before {
content: '';
position: absolute;
inset: 0;
background: inherit;
mix-blend-mode: multiply;
opacity: 0.6;
background-color: var(--glitch-red);
clip-path: polygon(0 20%, 100% 15%, 100% 45%, 0 50%);
transform: translate(8px, 0);
z-index: 2;
}
/* Blue channel ghost */
.datamosh::after {
content: '';
position: absolute;
inset: 0;
background: inherit;
mix-blend-mode: screen;
opacity: 0.5;
background-color: var(--glitch-blue);
clip-path: polygon(0 55%, 100% 60%, 100% 80%, 0 75%);
transform: translate(-6px, 0);
z-index: 2;
}
/* Animated variant */
.datamosh--animated::before {
animation: mosh-slice-a 2.5s steps(1) infinite;
}
.datamosh--animated::after {
animation: mosh-slice-b 3s steps(1) infinite;
}
@keyframes mosh-slice-a {
0% { clip-path: polygon(0 20%, 100% 15%, 100% 45%, 0 50%); transform: translate(8px, 0); }
25% { clip-path: polygon(0 50%, 100% 55%, 100% 70%, 0 65%); transform: translate(-5px, 0); }
50% { clip-path: polygon(0 10%, 100% 5%, 100% 25%, 0 30%); transform: translate(10px, 0); }
75% { clip-path: polygon(0 70%, 100% 75%, 100% 90%, 0 85%); transform: translate(-3px, 0); }
}
@keyframes mosh-slice-b {
0% { clip-path: polygon(0 55%, 100% 60%, 100% 80%, 0 75%); transform: translate(-6px, 0); }
33% { clip-path: polygon(0 30%, 100% 25%, 100% 50%, 0 55%); transform: translate(7px, 0); }
66% { clip-path: polygon(0 80%, 100% 85%, 100% 95%, 0 90%); transform: translate(-9px, 0); }
}
@media (prefers-reduced-motion: reduce) {
.datamosh--animated::before,
.datamosh--animated::after {
animation: none;
}
}
A pure CSS animated noise background using SVG filters, creating a subtle static grain effect across any element.
.noise-bg {
position: relative;
isolation: isolate;
}
.noise-bg::before {
content: '';
position: absolute;
inset: 0;
z-index: -1;
opacity: 0.06;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
background-repeat: repeat;
pointer-events: none;
}
/* Animated grain variant */
.noise-bg--animated::before {
animation: noise-shift 0.5s steps(4) infinite;
}
@keyframes noise-shift {
0% { transform: translate(0, 0); }
25% { transform: translate(-5%, -5%); }
50% { transform: translate(5%, 2%); }
75% { transform: translate(-2%, 5%); }
100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
.noise-bg--animated::before {
animation: none;
}
}
prefers-reduced-motion – always provide a static fallback for every animated effect; users with motion sensitivity must be able to experience the design without discomfort@media queries to simplify or disable heavy effects on smaller screens| Aesthetic | Relationship |
|---|---|
| Cyberpunk | Shares the neon-on-dark palette and dystopian digital atmosphere; Cyberpunk builds narrative worlds while Glitch Art focuses on the material breakdown of the medium itself |
| Vaporwave | Both reference digital artifacts and retro technology, but Vaporwave uses pastels and ironic nostalgia where Glitch Art embraces raw, aggressive corruption |
| Y2K Futurism | Both celebrate digital technology as a visual subject; Y2K looks forward with optimism while Glitch Art exposes the fragility behind the polished interface |
| Terminal CLI Aesthetic | Shares monospaced typography and the foregrounding of digital infrastructure; Terminal is ordered and systematic while Glitch Art breaks those systems apart |
| Weirdcore | Both create unsettling digital imagery through distortion and corruption, but Weirdcore targets surreal emotional discomfort while Glitch Art celebrates technical materiality |
| Low Poly | Both foreground the building blocks of digital graphics (polygons vs. pixels); Low Poly is geometric and controlled, Glitch Art is chaotic and deconstructive |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Glitch Art Template</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&family=VT323&display=swap" rel="stylesheet">
<style>
/* --- Custom Properties --- */
:root {
--glitch-void: #0d0d0d;
--glitch-screen-dark: #1a1a2e;
--glitch-static-gray: #2a2a2a;
--glitch-red: #ff0040;
--glitch-green: #00ff41;
--glitch-blue: #0080ff;
--glitch-cyan: #00ffff;
--glitch-magenta: #ff00ff;
--glitch-pink: #ff2e97;
--glitch-yellow: #f5f500;
--glitch-purple: #7b2fbe;
--glitch-orange: #ff6b2b;
--glitch-white: #ffffff;
--glitch-text: #e0e0e0;
--glitch-muted: #444444;
}
/* --- Reset --- */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Share Tech Mono', 'Courier New', Courier, monospace;
font-size: 16px;
line-height: 1.7;
color: var(--glitch-text);
background-color: var(--glitch-void);
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
h1, h2, h3, h4 {
font-family: 'Orbitron', 'Arial Black', sans-serif;
text-transform: uppercase;
letter-spacing: 0.08em;
line-height: 1.1;
color: var(--glitch-white);
}
a {
color: var(--glitch-cyan);
text-decoration: none;
transition: color 0.15s ease;
}
a:hover {
color: var(--glitch-magenta);
}
::selection {
background-color: var(--glitch-magenta);
color: var(--glitch-white);
}
/* --- Navigation --- */
.nav {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 2rem;
background-color: var(--glitch-void);
border-bottom: 1px solid var(--glitch-muted);
}
.nav::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(
90deg,
var(--glitch-cyan),
var(--glitch-magenta),
var(--glitch-green),
var(--glitch-cyan)
);
background-size: 200% 100%;
animation: interference-line 3s linear infinite;
}
@keyframes interference-line {
0% { background-position: 0% 0%; }
100% { background-position: 200% 0%; }
}
.nav .logo {
font-family: 'Orbitron', sans-serif;
font-size: 1rem;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 0.25em;
color: var(--glitch-white);
}
.nav ul {
list-style: none;
display: flex;
gap: 0;
}
.nav a {
display: block;
padding: 0.5rem 1.2rem;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--glitch-text);
}
.nav a:hover {
color: var(--glitch-cyan);
text-shadow:
2px 0 var(--glitch-red),
-2px 0 var(--glitch-blue);
}
/* --- Hero --- */
.hero {
position: relative;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
padding: 4rem 3rem;
overflow: hidden;
}
/* Scan lines */
.hero::after {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 2px,
rgba(0, 0, 0, 0.12) 2px,
rgba(0, 0, 0, 0.12) 4px
);
pointer-events: none;
z-index: 2;
}
.hero-content {
position: relative;
z-index: 3;
max-width: 900px;
}
/* RGB Split Headline */
.hero-title {
font-size: clamp(3rem, 9vw, 8rem);
font-weight: 900;
line-height: 0.95;
position: relative;
display: inline-block;
}
.hero-title::before,
.hero-title::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.hero-title::before {
color: var(--glitch-red);
mix-blend-mode: screen;
animation: glitch-r 3s infinite;
}
.hero-title::after {
color: var(--glitch-blue);
mix-blend-mode: screen;
animation: glitch-b 3s infinite;
}
@keyframes glitch-r {
0%, 100% { transform: translate(-2px, 0); clip-path: inset(0 0 0 0); }
20% { transform: translate(3px, 1px); clip-path: inset(25% 0 55% 0); }
40% { transform: translate(-1px, -1px); clip-path: inset(0 0 0 0); }
60% { transform: translate(4px, 0); clip-path: inset(60% 0 5% 0); }
80% { transform: translate(-2px, 1px); clip-path: inset(0 0 0 0); }
}
@keyframes glitch-b {
0%, 100% { transform: translate(2px, 0); clip-path: inset(0 0 0 0); }
20% { transform: translate(-3px, -1px); clip-path: inset(50% 0 20% 0); }
40% { transform: translate(1px, 1px); clip-path: inset(0 0 0 0); }
60% { transform: translate(-4px, 0); clip-path: inset(10% 0 70% 0); }
80% { transform: translate(2px, -1px); clip-path: inset(0 0 0 0); }
}
.hero-sub {
font-size: clamp(0.9rem, 1.5vw, 1.15rem);
max-width: 50ch;
margin-top: 1.5rem;
color: var(--glitch-text);
line-height: 1.8;
}
.hero-sub span {
color: var(--glitch-cyan);
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 2.5rem;
}
/* --- Buttons --- */
.btn {
position: relative;
display: inline-block;
font-family: 'Orbitron', sans-serif;
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.15em;
padding: 0.85rem 2rem;
border: 1px solid var(--glitch-cyan);
background-color: transparent;
color: var(--glitch-cyan);
cursor: pointer;
text-decoration: none;
overflow: hidden;
transition: background-color 0.2s ease, color 0.2s ease;
}
.btn:hover {
background-color: var(--glitch-cyan);
color: var(--glitch-void);
animation: btn-shake 0.3s ease;
}
@keyframes btn-shake {
0% { transform: translate(0); }
20% { transform: translate(-3px, 2px); }
40% { transform: translate(2px, -1px); }
60% { transform: translate(-1px, 1px); }
80% { transform: translate(1px, -2px); }
100% { transform: translate(0); }
}
.btn--alt {
border-color: var(--glitch-pink);
color: var(--glitch-pink);
}
.btn--alt:hover {
background-color: var(--glitch-pink);
color: var(--glitch-void);
}
/* --- Section --- */
.section {
position: relative;
padding: 5rem 3rem;
border-top: 1px solid var(--glitch-muted);
}
.section h2 {
font-size: clamp(1.8rem, 4vw, 3rem);
margin-bottom: 1rem;
color: var(--glitch-cyan);
}
.section > p {
max-width: 65ch;
margin-bottom: 2rem;
line-height: 1.8;
}
/* Section label */
.section-label {
font-family: 'Share Tech Mono', monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.25em;
color: var(--glitch-muted);
margin-bottom: 0.5rem;
display: block;
}
/* --- Card Grid --- */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1px;
background-color: var(--glitch-muted);
border: 1px solid var(--glitch-muted);
}
.card {
position: relative;
background-color: var(--glitch-screen-dark);
padding: 2rem;
overflow: hidden;
transition: transform 0.15s ease;
}
/* Scan lines on cards */
.card::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 2px,
rgba(0, 0, 0, 0.1) 2px,
rgba(0, 0, 0, 0.1) 4px
);
pointer-events: none;
z-index: 1;
}
.card:hover {
transform: translate(-2px, -1px);
box-shadow:
3px 0 0 var(--glitch-red),
-3px 0 0 var(--glitch-blue);
}
.card h3 {
position: relative;
z-index: 2;
font-size: 1rem;
letter-spacing: 0.1em;
color: var(--glitch-cyan);
margin-bottom: 0.75rem;
}
.card p {
position: relative;
z-index: 2;
font-size: 0.88rem;
line-height: 1.7;
margin-bottom: 1rem;
}
.card .tag {
display: inline-block;
position: relative;
z-index: 2;
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.12em;
padding: 0.2rem 0.5rem;
border: 1px solid var(--glitch-muted);
color: var(--glitch-green);
margin-right: 0.3rem;
margin-bottom: 0.3rem;
}
/* --- Data Table --- */
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.data-table th,
.data-table td {
border: 1px solid var(--glitch-muted);
padding: 0.75rem 1rem;
text-align: left;
}
.data-table th {
background-color: var(--glitch-screen-dark);
color: var(--glitch-cyan);
font-family: 'Orbitron', sans-serif;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.15em;
font-weight: 700;
}
.data-table tr:hover td {
background-color: rgba(0, 255, 255, 0.04);
}
.data-table td:first-child {
color: var(--glitch-white);
}
/* --- Corrupted Divider --- */
.divider {
position: relative;
height: 4px;
background: var(--glitch-muted);
margin: 0;
overflow: hidden;
}
.divider::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(
90deg,
var(--glitch-cyan) 0%,
var(--glitch-pink) 25%,
var(--glitch-void) 30%,
var(--glitch-void) 45%,
var(--glitch-green) 50%,
var(--glitch-void) 55%,
var(--glitch-void) 70%,
var(--glitch-magenta) 75%,
var(--glitch-cyan) 100%
);
animation: divider-scan 4s linear infinite;
background-size: 200% 100%;
}
@keyframes divider-scan {
0% { background-position: 0% 0%; }
100% { background-position: 200% 0%; }
}
/* --- Signal Interference Banner --- */
.interference {
position: relative;
padding: 2.5rem 3rem;
background-color: var(--glitch-screen-dark);
border-top: 1px solid var(--glitch-muted);
border-bottom: 1px solid var(--glitch-muted);
overflow: hidden;
text-align: center;
}
.interference::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 300%;
height: 100%;
background: repeating-linear-gradient(
90deg,
transparent 0px,
transparent 3px,
rgba(0, 255, 255, 0.03) 3px,
rgba(0, 255, 255, 0.03) 6px
);
animation: h-scan 2s linear infinite;
pointer-events: none;
}
@keyframes h-scan {
0% { transform: translateX(0); }
100% { transform: translateX(33.33%); }
}
.interference .display-text {
font-family: 'VT323', monospace;
font-size: clamp(1.5rem, 3vw, 2.5rem);
color: var(--glitch-green);
letter-spacing: 0.15em;
text-transform: uppercase;
position: relative;
z-index: 2;
}
/* --- Footer --- */
.footer {
padding: 2.5rem 3rem;
border-top: 1px solid var(--glitch-muted);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
}
.footer p {
font-size: 0.78rem;
color: var(--glitch-muted);
}
.footer a {
color: var(--glitch-text);
margin-left: 1.5rem;
font-size: 0.78rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.footer a:hover {
color: var(--glitch-cyan);
}
/* --- Utilities --- */
.mt-1 { margin-top: 1rem; }
.mt-2 { margin-top: 2rem; }
.text-cyan { color: var(--glitch-cyan); }
.text-pink { color: var(--glitch-pink); }
.text-green { color: var(--glitch-green); }
/* --- Reduced Motion --- */
@media (prefers-reduced-motion: reduce) {
.hero-title::before,
.hero-title::after {
animation: none;
transform: translate(0);
clip-path: inset(0 0 0 0);
}
.hero-title::before { transform: translate(-2px, 0); }
.hero-title::after { transform: translate(2px, 0); }
.nav::after { animation: none; }
.divider::before { animation: none; }
.interference::before { animation: none; }
.btn:hover { animation: none; }
}
/* --- Responsive --- */
@media (max-width: 768px) {
.hero {
min-height: 80vh;
padding: 3rem 1.5rem;
}
.section {
padding: 3rem 1.5rem;
}
.nav {
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
padding: 1rem 1.5rem;
}
.nav ul {
flex-wrap: wrap;
}
.card-grid {
grid-template-columns: 1fr;
}
.footer {
flex-direction: column;
align-items: flex-start;
padding: 2rem 1.5rem;
}
.footer a {
margin-left: 0;
margin-right: 1rem;
}
}
</style>
</head>
<body>
<!-- NAVIGATION -->
<nav class="nav">
<span class="logo">GL//TCH</span>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#data">Data</a></li>
<li><a href="#signal">Signal</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<!-- HERO -->
<section class="hero">
<div class="hero-content">
<h1 class="hero-title" data-text="Glitch Art">Glitch Art</h1>
<p class="hero-sub">
The beauty of <span>broken data</span>. We find aesthetics in
technological failure -- pixel corruption, signal interference,
and the hidden structures revealed when digital systems malfunction.
This is not an error. This is the message.
</p>
<div class="hero-actions">
<a href="#projects" class="btn">Explore Projects</a>
<a href="#data" class="btn btn--alt">View Data</a>
</div>
</div>
</section>
<!-- CORRUPTED DIVIDER -->
<div class="divider"></div>
<!-- ABOUT -->
<section class="section" id="about">
<span class="section-label">// 001 — About</span>
<h2>Error as Aesthetic</h2>
<p>
Glitch Art transforms technological failure into a creative medium.
By deliberately inducing or capturing malfunctions in digital systems,
we expose the hidden mechanics of the tools we use every day.
Datamoshing, pixel sorting, RGB channel splitting, and data bending
are not bugs to be fixed -- they are the raw material of a new
visual language.
</p>
</section>
<!-- PROJECTS -->
<section class="section" id="projects">
<span class="section-label">// 002 — Projects</span>
<h2>Projects</h2>
<p>
Each project explores a different facet of digital disruption.
Hover to corrupt.
</p>
<div class="card-grid mt-2">
<div class="card">
<h3>Datamosh Engine</h3>
<p>A real-time video corruption tool that removes I-frames from compressed video streams, producing the flowing, painterly distortions of datamoshing in the browser.</p>
<span class="tag">Video</span>
<span class="tag">WebCodecs</span>
<span class="tag">Real-time</span>
</div>
<div class="card">
<h3>Hex Painter</h3>
<p>Open any image file as raw hexadecimal data and paint directly into the byte stream. Watch the image reconstruct with each corrupted edit.</p>
<span class="tag">Data Bending</span>
<span class="tag">Canvas</span>
</div>
<div class="card">
<h3>Channel Drift</h3>
<p>An interactive installation that separates the red, green, and blue channels of a live webcam feed and maps each to independent mouse-controlled offsets.</p>
<span class="tag">RGB Split</span>
<span class="tag">WebGL</span>
<span class="tag">Interactive</span>
</div>
<div class="card">
<h3>Signal Decay</h3>
<p>Generative compositions that simulate electromagnetic interference, scan line degradation, and VHS tracking errors using pure CSS and SVG filters.</p>
<span class="tag">Generative</span>
<span class="tag">CSS</span>
<span class="tag">SVG</span>
</div>
<div class="card">
<h3>Codec Autopsy</h3>
<p>A visual explainer that deconstructs JPEG, PNG, and WebP compression in real time, revealing the block artifacts and quantization tables hidden inside every image.</p>
<span class="tag">Compression</span>
<span class="tag">Education</span>
</div>
<div class="card">
<h3>Pixel Sort Lab</h3>
<p>Upload an image and apply pixel sorting algorithms -- by brightness, hue, or saturation -- to create the cascading, waterfall-like distortions of sorted pixel rows.</p>
<span class="tag">Pixel Sorting</span>
<span class="tag">WASM</span>
</div>
</div>
</section>
<!-- SIGNAL INTERFERENCE BANNER -->
<div class="interference" id="signal">
<div class="display-text">██ Signal Acquired — Corruption Level: 87% ██</div>
</div>
<!-- DATA TABLE -->
<section class="section" id="data">
<span class="section-label">// 003 — Data</span>
<h2>Corruption Index</h2>
<p>
Measured distortion parameters across active signal channels.
</p>
<table class="data-table mt-2">
<thead>
<tr>
<th>Channel</th>
<th>Offset</th>
<th>Noise Floor</th>
<th>Artifact Rate</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>RED</td>
<td>+3px / -1px</td>
<td>0.042</td>
<td>12.7/sec</td>
<td class="text-pink">CORRUPTED</td>
</tr>
<tr>
<td>GREEN</td>
<td>+0px / +2px</td>
<td>0.018</td>
<td>3.1/sec</td>
<td class="text-green">NOMINAL</td>
</tr>
<tr>
<td>BLUE</td>
<td>-2px / +1px</td>
<td>0.037</td>
<td>9.4/sec</td>
<td class="text-cyan">DEGRADED</td>
</tr>
<tr>
<td>ALPHA</td>
<td>+0px / +0px</td>
<td>0.003</td>
<td>0.2/sec</td>
<td class="text-green">NOMINAL</td>
</tr>
<tr>
<td>SYNC</td>
<td>+7px / -4px</td>
<td>0.089</td>
<td>24.1/sec</td>
<td class="text-pink">CRITICAL</td>
</tr>
</tbody>
</table>
</section>
<!-- CONTACT -->
<section class="section" id="contact">
<span class="section-label">// 004 — Contact</span>
<h2>Transmit</h2>
<p>
Signal endpoint: <a href="mailto:glitch@example.com">glitch@example.com</a>
— Source: <a href="#">view repository</a>
— License: MIT
</p>
</section>
<!-- FOOTER -->
<footer class="footer">
<p>© 2026 GL//TCH — Error is the message.</p>
<nav>
<a href="#">Top</a>
<a href="#">Source</a>
<a href="#">RSS</a>
</nav>
</footer>
</body>
</html>