Angelic grunge
Loved this frosty, corroded look where the letters are eaten by texture and the edges melt off into a soft mist. So I built it from the ground up.
Real grunge scans (a cracked frost and a spatter of blooms) carve holes and cracks into the word, and a soft frosty halo blooms off the edges into the paper. The whole thing sits in a cold duotone. The frost slowly creeps on its own, and moving over it clears the frost so a cleaner letter shows through. Type your own word and pick the two colors below.
Playground
Word
Grunge
Duotone
Code
// Angelic Grunge presets + Remix. Each preset is a duotone ink on a suited paper with its
// own grunge amount / frost bloom. Remix keeps the frost-erosion mechanic but rolls a
// fresh cold-or-warm duotone on a matching sheet.
import { GRUNGE_DEFAULTS, type GrungeParams } from "./engine";
export type GrungePreset = { id: string; name: string; params: Partial<GrungeParams> };
export const GRUNGE_PRESETS: GrungePreset[] = [
{
id: "angelic",
name: "Angelic",
// the source look: cold blue-teal frost on cool white (the default)
params: { ink: [0.09, 0.16, 0.22], paper: [0.99, 0.99, 1.0], grunge: 0.55, bloom: 0.5, grain: 0.06 },
},
{
id: "rust",
name: "Rust",
// corroded warm rust-brown on aged paper
params: { ink: [0.28, 0.13, 0.06], paper: [0.96, 0.93, 0.86], grunge: 0.62, bloom: 0.45, grain: 0.08 },
},
{
id: "mono",
name: "Mono",
// pure black corrosion on white
params: { ink: [0.06, 0.06, 0.07], paper: [1.0, 1.0, 1.0], grunge: 0.6, bloom: 0.4, grain: 0.05 },
},
{
id: "toxic",
name: "Toxic",
// acid green corrosion on a dark charcoal sheet
params: { ink: [0.5, 0.85, 0.2], paper: [0.08, 0.09, 0.08], grunge: 0.58, bloom: 0.55, grain: 0.07 },
},
{
id: "ember",
name: "Ember",
// hot orange-red burn on near-black
params: { ink: [0.95, 0.42, 0.14], paper: [0.07, 0.06, 0.07], grunge: 0.64, bloom: 0.6, grain: 0.08 },
},
{
id: "violet",
name: "Violet",
// deep violet frost on pale lilac
params: { ink: [0.24, 0.12, 0.36], paper: [0.96, 0.95, 0.98], grunge: 0.52, bloom: 0.5, grain: 0.06 },
},
];
export function defaultGrungeParams(): GrungeParams {
return { ...GRUNGE_DEFAULTS, ...GRUNGE_PRESETS[0].params };
}
// rgb 0..1 <-> #hex for the ColorControl (which speaks hex)
export const toHex = (c: [number, number, number]) =>
"#" + c.map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0")).join("");
export const fromHex = (h: string): [number, number, number] => {
const n = h.replace("#", "");
return [0, 2, 4].map((i) => parseInt(n.slice(i, i + 2) || "0", 16) / 255) as [number, number, number];
};
// a saturated-but-dark ink hue (reads as corroded ink, not a pastel)
function inkHue(hue: number): [number, number, number] {
const c = 1;
const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));
const seg = [
[c, x, 0], [x, c, 0], [0, c, x], [0, x, c], [x, 0, c], [c, 0, x],
][Math.floor(hue / 60) % 6];
return [seg[0] * 0.4 + 0.06, seg[1] * 0.4 + 0.06, seg[2] * 0.4 + 0.06];
}
// Remix: a fresh duotone. ~1 in 3 rolls a DARK sheet (light ink on dark), else a light
// paper (dark ink on light), with varied grunge + bloom.
export function remixGrungeParams(): Partial<GrungeParams> {
const h = Math.random() * 360;
const darkSheet = Math.random() < 0.34;
let ink: [number, number, number];
let paper: [number, number, number];
if (darkSheet) {
// a vivid ink on a near-black sheet (glows out of the dark)
const c = 1;
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
const seg = [[c, x, 0], [x, c, 0], [0, c, x], [0, x, c], [x, 0, c], [c, 0, x]][Math.floor(h / 60) % 6];
ink = [seg[0] * 0.8 + 0.15, seg[1] * 0.8 + 0.15, seg[2] * 0.8 + 0.15];
paper = [0.07, 0.07, 0.08];
} else {
ink = inkHue(h);
// a light sheet faintly tinted toward the ink hue so they feel paired
const m = Math.max(ink[0], ink[1], ink[2], 0.001);
paper = [0.96 + (ink[0] / m) * 0.03, 0.96 + (ink[1] / m) * 0.03, 0.96 + (ink[2] / m) * 0.03];
}
return {
ink,
paper,
grunge: 0.45 + Math.random() * 0.3,
bloom: 0.35 + Math.random() * 0.35,
grain: 0.04 + Math.random() * 0.06,
};
}
Credits
CompanyStudy
DateJul 14, 2026
TagsWebGL, Grunge, Texture
MIT → free to copy