Extruded Type Tilt
Display type with a solid extrusion that swings around as the pointer moves.
- Category
- Text Effects
- Added
- 2026-09-20
- Deps
- none
- Updated
- 2026-09-20
Props
"use client";
import { useRef, useState } from "react";
export function ExtrudedTypeTilt({
text,
layers = 10,
depth = 2.2,
accentFace = true,
}: {
text: string;
layers?: number;
depth?: number;
/** Bright front face. Off, the face sits closer to the extrusion tone. */
accentFace?: boolean;
}) {
const boxRef = useRef<HTMLDivElement>(null);
// Extrusion direction. Defaults to down-right — the conventional light
// position — so the solid reads correctly before any pointer input.
const [dir, setDir] = useState({ x: 0.7, y: 0.7 });
function handleMove(e: React.MouseEvent<HTMLDivElement>) {
const rect = boxRef.current?.getBoundingClientRect();
if (!rect) return;
const nx = (e.clientX - rect.left) / rect.width - 0.5;
const ny = (e.clientY - rect.top) / rect.height - 0.5;
// Inverted, so the extrusion trails AWAY from the cursor like a shadow
// cast by it rather than leaning toward it.
setDir({ x: -nx * 2, y: -ny * 2 });
}
return (
<div
ref={boxRef}
onMouseMove={handleMove}
onMouseLeave={() => setDir({ x: 0.7, y: 0.7 })}
className="flex cursor-default select-none items-center justify-center"
>
<span className="relative block text-6xl font-black leading-none tracking-tight">
<span className="sr-only">{text}</span>
<span aria-hidden>
{/*
* The depth is N stacked copies, each offset one step further along
* the light direction and darkened. Because only the OFFSET
* direction changes, the solid appears to rotate without any real
* 3D — no perspective, no preserve-3d, and so no GPU rasterisation
* blurring the glyph edges at fractional transforms.
* Furthest layer paints first so nearer ones cover it.
*/}
{Array.from({ length: layers }).map((_, i) => {
const step = layers - i;
return (
<span
key={i}
className="absolute inset-0 block transition-transform duration-200 ease-out"
style={{
transform:
"translate(" +
dir.x * depth * step +
"px, " +
dir.y * depth * step +
"px)",
color: "rgba(61,123,255," + (0.06 + (i / layers) * 0.3) + ")",
}}
>
{text}
</span>
);
})}
{/* Front face, drawn last and unoffset. */}
<span
className="relative block"
style={{ color: accentFace ? "#e8eaee" : "#9aa3b2" }}
>
{text}
</span>
</span>
</span>
</div>
);
}
About this text effect
The obvious way to build extruded type that turns with the cursor is real 3D — perspective on the container, preserve-3d, a rotation on two axes. It also looks worse, because the moment text is rotated in 3D the browser rasterises it to a texture and the glyph edges go soft, which is exactly the wrong outcome for display type whose whole appeal is its crispness. This fakes the rotation instead: the depth is a stack of flat copies, each offset one step further along a direction vector and darkened, and only that direction changes with the pointer. The solid appears to swing while every layer stays a normally-rendered, sub-pixel-antialiased glyph. Paint order matters — the furthest layer goes down first so nearer ones cover it, otherwise the side wall reads inside out. Defaulting the direction to down-right gives it a conventional light position at rest and on mouse leave, so it never looks unlit. The trade-off is duplication: a dozen layers is a dozen copies of the word, so it belongs on one short headline and needs a single hidden copy carrying the real string.
Curator’s note
Built for viberdy 2.0. Faking the rotation with offset direction instead of real 3D is what keeps the glyph edges razor sharp.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Scramble Text
text effectsText that decodes from random characters into its real word on hover.
Glitch Text Hover
text effectsAn RGB-split, jittery glitch effect on text when you hover it.
Slice Shear Hover
text effectsDisplay type cut into horizontal bands that fan apart under the pointer.