Two modes of the same idea: making letterforms look liquid. Inflate mode chains an SVG feMorphology dilate, a Gaussian blur, and a high-pass colour matrix (alpha channel: 18x - 7) to round off sharp edges into blobby, inflated shapes, with an optional ring variant that composites dilate-out to produce a thick organic border. Goo mode takes the CSS shortcut -- blur the text, then crank contrast to 20 on a same-colour background -- collapsing the blur fringe into gooey metaball edges.
Source
"use client";
import { useId, useState } from "react";
import ScrambleLink from "../ScrambleLink";
import DraggablePanel from "../DraggablePanel";
import { PanelColor, PanelSelect, PanelToggle, PanelText } from "../_kansei/controls";
import { FONT_STYLES, type FontChoice } from "../_kansei/fonts";
const ALPHA = "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7";
export default function Melt() {
const [mode, setMode] = useState<"inflate" | "goo">("inflate");
const [dilateRadius, setDilateRadius] = useState(2);
const [blurAmount, setBlurAmount] = useState(4);
const [fontSize, setFontSize] = useState(96);
const [font, setFont] = useState<FontChoice>("display");
const [blobText, setBlobText] = useState("Kansei");
const [showBorder, setShowBorder] = useState(false);
const [textColor, setTextColor] = useState("#5b7fc4");
const [borderColor, setBorderColor] = useState("#3a5fa0");
const [borderWidth, setBorderWidth] = useState(4);
const [bgColor, setBgColor] = useState("#f0e8d8");
const uid = useId().replace(/:/g, "");
const inflateId = `blob-inflate-${uid}`;
const ringId = `blob-ring-${uid}`;
const fontStyle = FONT_STYLES[font];
return (
<div className="fixed inset-0 flex items-center justify-center select-none" style={{ background: bgColor }}>
{/* filter defs */}
<svg width="0" height="0" style={{ position: "absolute" }} aria-hidden>
<defs>
<filter id={inflateId} x="-20%" y="-20%" width="140%" height="140%">
<feMorphology operator="dilate" radius={dilateRadius} result="dilated" />
<feGaussianBlur in="dilated" stdDeviation={blurAmount * 0.5} result="blurred" />
<feComposite in="blurred" in2="SourceGraphic" operator="over" result="withOutline" />
<feColorMatrix in="withOutline" type="matrix" values={ALPHA} />
</filter>
<filter id={ringId} x="-25%" y="-25%" width="150%" height="150%">
<feMorphology operator="dilate" radius={dilateRadius} result="dilated" />
<feGaussianBlur in="dilated" stdDeviation={blurAmount * 0.5} result="blurred" />
<feComposite in="blurred" in2="SourceGraphic" operator="over" result="comp" />
<feColorMatrix in="comp" type="matrix" values={ALPHA} result="blob" />
<feFlood floodColor={borderColor} result="flood" />
<feComposite in="flood" in2="blob" operator="in" result="ink" />
<feMorphology operator="dilate" in="ink" radius={borderWidth} result="outer" />
<feComposite in="outer" in2="blob" operator="out" />
</filter>
</defs>
</svg>
{mode === "inflate" ? (
<div className="relative flex items-center justify-center z-[1]" style={{ height: fontSize * 2 }}>
<span
aria-hidden
className="block text-center font-black leading-none"
style={{ fontSize, color: textColor, filter: `url(#${showBorder ? ringId : inflateId})`, position: "absolute", ...fontStyle }}
>
{blobText}
</span>
<span
className="block text-center font-black leading-none"
style={{ fontSize, color: showBorder ? "transparent" : textColor, position: "relative", zIndex: 1, ...fontStyle }}
>
{blobText}
</span>
</div>
) : (
<div
className="z-[1] flex items-center justify-center"
style={{ filter: `blur(${blurAmount}px) contrast(20)`, background: bgColor, height: fontSize * 2, padding: "0 40px" }}
>
<span className="block text-center font-black leading-none" style={{ fontSize, color: textColor, ...fontStyle }}>
{blobText}
</span>
</div>
)}
<div
className="fixed bottom-8 left-8 pointer-events-none z-10 font-[family-name:var(--font-flux)]"
style={{ fontVariationSettings: "'wght' 300, 'SRIF' 100" }}
>
<p className="text-[12px] tracking-[0.08em] uppercase text-foreground/50">Melt</p>
<p className="text-[12px] tracking-[0.08em] mt-1 text-foreground/30">{mode}</p>
</div>
<DraggablePanel
isLight={false}
controls={[
{ label: "Font size", value: fontSize, set: (v) => setFontSize(Math.round(v)), min: 48, max: 200, step: 1 },
{ label: "Dilate", value: dilateRadius, set: setDilateRadius, min: 0, max: 10, step: 0.5 },
{ label: "Blur", value: blurAmount, set: setBlurAmount, min: 0, max: 16, step: 0.5 },
{ label: "Border width", value: borderWidth, set: (v) => setBorderWidth(Math.round(v)), min: 1, max: 16, step: 1 },
]}
>
<PanelText label="Text" value={blobText} set={setBlobText} placeholder="Kansei" isLight={false} />
<PanelSelect label="Mode" value={mode} options={["inflate", "goo"] as const} set={setMode} isLight={false} />
<PanelSelect label="Font" value={font} options={["display", "sans", "noto"] as const} set={setFont} isLight={false} />
<PanelToggle label="Border (inflate)" value={showBorder} set={setShowBorder} isLight={false} />
<PanelColor label="Text" value={textColor} set={setTextColor} isLight={false} />
<PanelColor label="Border" value={borderColor} set={setBorderColor} isLight={false} />
<PanelColor label="Background" value={bgColor} set={setBgColor} isLight={false} />
</DraggablePanel>
<div className="fixed top-8 left-8 z-10">
<ScrambleLink
from="NEMAWASHI LAB"
to="← BACK"
href="/lab"
className="text-[14px] tracking-[0.08em] uppercase pointer-events-auto font-[family-name:var(--font-flux)] text-foreground/60"
style={{ fontVariationSettings: "'wght' 600, 'SRIF' 400" }}
/>
</div>
</div>
);
}