Workspace / component / shaders
Metaballs Shader
paxfx add blocks/component-shaders-metaballslocal onlyTier: high. Reduced motion: Blobs rest in a fixed composition.
"use client";
import type { ReactNode } from "react";
import { cn, EffectSurface } from "@pax-sh/blocks";
export interface MetaballsShaderProps {
className?: string;
/** Content the blobs melt across. Defaults to a demo panel. */
children?: ReactNode;
}
function DemoContent() {
return (
<div className="flex min-h-[320px] flex-col justify-center gap-5 p-8 md:p-12">
<p className="m-0 text-xs font-medium uppercase tracking-[0.22em] text-[var(--pax-acid,#c8ff00)]">
Surface tension / field render
</p>
<h3 className="m-0 max-w-xl text-3xl font-semibold leading-tight tracking-tight [text-wrap:balance] md:text-4xl">
Blobs that actually merge.
</h3>
<p className="m-0 max-w-md text-sm leading-relaxed text-[var(--pax-paper,#f6f2ea)] opacity-70">
The bubble engine evaluates a scalar field and thresholds it, so two blobs near each other
neck together the way real fluids do instead of just overlapping.
</p>
<div className="mt-2 flex flex-wrap gap-2">
{["Threshold field", "Organic motion", "Runs over HTML"].map((label) => (
<span
key={label}
className="rounded-full border px-3 py-1 text-[11px] font-medium uppercase tracking-[0.14em] text-[var(--pax-paper,#f6f2ea)]"
style={{ borderColor: "color-mix(in srgb, var(--pax-paper,#f6f2ea) 22%, transparent)" }}
>
{label}
</span>
))}
</div>
</div>
);
}
/**
* Mounts the Pax bubble engine over live HTML: metaballs drift across the
* surface and melt together at surface-tension thresholds. Under reduced
* motion the blobs rest in a fixed composition.
*/
export function MetaballsShader({ className, children }: MetaballsShaderProps) {
return (
<div
className={cn(
"relative isolate overflow-hidden rounded-2xl border border-[var(--pax-border,rgba(18,17,15,0.12))]",
"bg-[var(--pax-night,#0b0d10)] text-[var(--pax-paper,#f6f2ea)]",
className,
)}
data-pax-asset="component-shaders-metaballs"
>
<EffectSurface effect="bubble" tier="high" className="h-full w-full">
{children ?? <DemoContent />}
</EffectSurface>
</div>
);
}