11 / 30
All 30 in 30 Tailwind CSS Text Hover Effects
- 01Tailwind CSS Animated Underline Hover Effect
- 02Tailwind Liquid Text Fill Hover Animation
- 03Tailwind Gradient Text Hover Effect with bg-clip-text
- 04Tailwind Animated Strikethrough Text Hover Effect
- 05Tailwind Text Swap and Flip Up Hover Effect
- 06Tailwind CSS Glitch Text Hover Effect
- 07Tailwind Neon Glow Text with Flicker Animation
- 08Tailwind Metallic Gold Shimmer Text Effect
- 09Tailwind 3D Text Pop and Lift Hover Effect
- 10Tailwind Staggered Letter Wave Hover Animation
- 11Tailwind Spotlight Text Reveal on Mouse Hover
- 12Tailwind Hover to Reveal Hidden Spoiler Text
- 13Tailwind Blur to Focus Text Hover Effect
- 14Tailwind Magnetic Hover Effect for Buttons and Text
- 15Tailwind Letter Spacing Expand on Hover (Tracking Animation)
- 16Tailwind Outline Text Stroke to Fill Hover Effect
- 17Tailwind Text Scramble and Matrix Decrypt Hover Effect
- 18Tailwind Animated Border Button Hover Effect
- 19Tailwind Elastic Rubber Band Text Hover Animation
- 20Tailwind Variable Font Weight Hover Animation
- 21Tailwind Animated Rainbow Gradient Text on Hover
- 22Tailwind 3D Perspective Tilt Text Hover Effect
- 23Tailwind Smoke Dissolve Text Hover Effect
- 24Tailwind Fire Text Effect with Heat Wave Glow
- 25Tailwind Dynamic Text Shadow that Follows the Cursor
- 26Tailwind Infinite Text Marquee that Speeds Up on Hover
- 27Tailwind Duotone Split Color Text Hover Effect
- 28Tailwind CSS Tooltip on Hover (No JavaScript)
- 29Tailwind SVG Water Ripple Distortion Text Effect
- 30Tailwind Clip-Path Text Reveal Hover Animation
Tailwind Spotlight Text Reveal on Mouse Hover
A night-photography headline where the cursor is a torch: a city photo lives inside the glyphs (bg-clip-text), hidden by a radial mask-image centred at var(--tth11-x) var(--tth11-y). A 12-line script writes the coordinates; Tailwind does everything else, including the typed radius that grows from 0 to 170px on hover.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tth-11 w-full min-h-svh grid place-items-center bg-tth11-bg bg-[radial-gradient(100%_80%_at_50%_100%,var(--color-tth11-glow),var(--color-tth11-bg)_65%)] px-5 py-14 font-tth11-sans text-tth11-ink" aria-label="Spotlight text reveal demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-xs font-bold uppercase tracking-[0.28em] text-tth11-mut">Night photography walks — booking winter 2026</p>
<a id="tth11-top" href="#tth11-top" data-tth11-torch class="group/torch relative inline-block rounded-md px-[0.12em] py-[0.1em] text-[clamp(52px,11.5vw,118px)] font-black leading-[1.02] tracking-[-0.02em] [font-stretch:115%] no-underline [--tth11-r:0px] focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-tth11-acc">
<span class="block text-tth11-bg [paint-order:stroke_fill] [-webkit-text-stroke:3px_color-mix(in_oklch,var(--color-tth11-ink)_45%,transparent)]">MIDNIGHT<br>ATLAS</span>
<span aria-hidden="true" style="--tth11-photo:url('https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?q=80&w=1600&auto=format&fit=crop')" class="absolute inset-0 block px-[0.12em] py-[0.1em] bg-[image:linear-gradient(oklch(0.5_0.1_260/0.35),oklch(0.5_0.1_260/0.35)),var(--tth11-photo),linear-gradient(120deg,var(--color-tth11-acc),oklch(0.6_0.18_300))] bg-cover bg-center bg-clip-text text-transparent [mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] [-webkit-mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] transition-[--tth11-r] duration-550 ease-[cubic-bezier(.3,.9,.2,1)] group-hover/torch:[--tth11-r:170px] group-focus-visible/torch:[--tth11-r:60em] pointer-coarse:[--tth11-r:60em] motion-reduce:transition-none">MIDNIGHT<br>ATLAS</span>
</a>
<a href="#tth11-top" class="inline-flex min-h-11 items-center gap-2 rounded-full bg-tth11-acc px-5 text-sm font-bold text-tth11-bg no-underline transition-[translate,box-shadow] duration-300 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_-8px_var(--color-tth11-acc)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tth11-acc">Reserve a walk <span aria-hidden="true">→</span></a>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth11-mut">Sweep the cursor across the letters — the photo lives inside the glyphs; a radial <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">mask-image</code> at <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">var(--tth11-x) var(--tth11-y)</code> is the torch. <kbd class="rounded-[5px] border border-b-2 border-white/15 bg-tth11-chip px-1.5 py-0.5 font-tth11-mono text-[11px]">Tab</kbd> floods it fully lit.</p>
</div>
</section><section class="tth-11 w-full min-h-svh grid place-items-center bg-tth11-bg bg-[radial-gradient(100%_80%_at_50%_100%,var(--color-tth11-glow),var(--color-tth11-bg)_65%)] px-5 py-14 font-tth11-sans text-tth11-ink" aria-label="Spotlight text reveal demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-xs font-bold uppercase tracking-[0.28em] text-tth11-mut">Night photography walks — booking winter 2026</p>
<a id="tth11-top" href="#tth11-top" data-tth11-torch class="group/torch relative inline-block rounded-md px-[0.12em] py-[0.1em] text-[clamp(52px,11.5vw,118px)] font-black leading-[1.02] tracking-[-0.02em] [font-stretch:115%] no-underline [--tth11-r:0px] focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-tth11-acc">
<span class="block text-tth11-bg [paint-order:stroke_fill] [-webkit-text-stroke:3px_color-mix(in_oklch,var(--color-tth11-ink)_45%,transparent)]">MIDNIGHT<br>ATLAS</span>
<span aria-hidden="true" style="--tth11-photo:url('https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?q=80&w=1600&auto=format&fit=crop')" class="absolute inset-0 block px-[0.12em] py-[0.1em] bg-[image:linear-gradient(oklch(0.5_0.1_260/0.35),oklch(0.5_0.1_260/0.35)),var(--tth11-photo),linear-gradient(120deg,var(--color-tth11-acc),oklch(0.6_0.18_300))] bg-cover bg-center bg-clip-text text-transparent [mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] [-webkit-mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] transition-[--tth11-r] duration-550 ease-[cubic-bezier(.3,.9,.2,1)] group-hover/torch:[--tth11-r:170px] group-focus-visible/torch:[--tth11-r:60em] pointer-coarse:[--tth11-r:60em] motion-reduce:transition-none">MIDNIGHT<br>ATLAS</span>
</a>
<a href="#tth11-top" class="inline-flex min-h-11 items-center gap-2 rounded-full bg-tth11-acc px-5 text-sm font-bold text-tth11-bg no-underline transition-[translate,box-shadow] duration-300 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_-8px_var(--color-tth11-acc)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tth11-acc">Reserve a walk <span aria-hidden="true">→</span></a>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth11-mut">Sweep the cursor across the letters — the photo lives inside the glyphs; a radial <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">mask-image</code> at <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">var(--tth11-x) var(--tth11-y)</code> is the torch. <kbd class="rounded-[5px] border border-b-2 border-white/15 bg-tth11-chip px-1.5 py-0.5 font-tth11-mono text-[11px]">Tab</kbd> floods it fully lit.</p>
</div>
</section>@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}(function () {
var wrap = document.querySelector('[data-tth11-torch]');
if (!wrap) return;
wrap.addEventListener('pointermove', function (e) {
var r = wrap.getBoundingClientRect();
wrap.style.setProperty('--tth11-x', (e.clientX - r.left) + 'px');
wrap.style.setProperty('--tth11-y', (e.clientY - r.top) + 'px');
});
wrap.addEventListener('pointerleave', function () {
wrap.style.removeProperty('--tth11-x');
wrap.style.removeProperty('--tth11-y');
});
})();(function () {
var wrap = document.querySelector('[data-tth11-torch]');
if (!wrap) return;
wrap.addEventListener('pointermove', function (e) {
var r = wrap.getBoundingClientRect();
wrap.style.setProperty('--tth11-x', (e.clientX - r.left) + 'px');
wrap.style.setProperty('--tth11-y', (e.clientY - r.top) + 'px');
});
wrap.addEventListener('pointerleave', function () {
wrap.style.removeProperty('--tth11-x');
wrap.style.removeProperty('--tth11-y');
});
})();Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@62..125,500..900&family=JetBrains+Mono:wght@400;600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@62..125,500..900&family=JetBrains+Mono:wght@400;600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The script now finds its target by
data-tth11-torchinstead of a BEM class, and writes namespaced--tth11-x/yso two demos on a page can't steal each other's pointer. .wrap:hover .beam{--cth11-r:170px}becamegroup-hover/torch:[--tth11-r:170px]; the radius@propertyis the only CSS left.- UI upgrade from the CSS original: touch screens get
pointer-coarse:[--tth11-r:60em]— the photo is fully revealed, instead of a hollow outline nobody can light. A gradient sits under the photo so a failed hotlink still glows. - UI upgrade: the hollow layer uses a 3px stroke under a stage-coloured fill (
[paint-order:stroke_fill]), hiding variable-font contour overlaps; Archivo Expanded at 115% width gives the torch more interior to light; and a real Reserve a walk CTA was added.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Spotlight Text Reveal on Mouse Hover
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-spotlight-text-reveal-on-mouse-hover/
A night-photography headline where the cursor is a torch: a city photo lives inside the glyphs (bg-clip-text), hidden by a radial mask-image centred at var(--tth11-x) var(--tth11-y). A 12-line script writes the coordinates; Tailwind does everything else, including the typed radius that grows from 0 to 170px on hover.
## HTML
```html
<section class="tth-11 w-full min-h-svh grid place-items-center bg-tth11-bg bg-[radial-gradient(100%_80%_at_50%_100%,var(--color-tth11-glow),var(--color-tth11-bg)_65%)] px-5 py-14 font-tth11-sans text-tth11-ink" aria-label="Spotlight text reveal demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-xs font-bold uppercase tracking-[0.28em] text-tth11-mut">Night photography walks — booking winter 2026</p>
<a id="tth11-top" href="#tth11-top" data-tth11-torch class="group/torch relative inline-block rounded-md px-[0.12em] py-[0.1em] text-[clamp(52px,11.5vw,118px)] font-black leading-[1.02] tracking-[-0.02em] [font-stretch:115%] no-underline [--tth11-r:0px] focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-tth11-acc">
<span class="block text-tth11-bg [paint-order:stroke_fill] [-webkit-text-stroke:3px_color-mix(in_oklch,var(--color-tth11-ink)_45%,transparent)]">MIDNIGHT<br>ATLAS</span>
<span aria-hidden="true" style="--tth11-photo:url('https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?q=80&w=1600&auto=format&fit=crop')" class="absolute inset-0 block px-[0.12em] py-[0.1em] bg-[image:linear-gradient(oklch(0.5_0.1_260/0.35),oklch(0.5_0.1_260/0.35)),var(--tth11-photo),linear-gradient(120deg,var(--color-tth11-acc),oklch(0.6_0.18_300))] bg-cover bg-center bg-clip-text text-transparent [mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] [-webkit-mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] transition-[--tth11-r] duration-550 ease-[cubic-bezier(.3,.9,.2,1)] group-hover/torch:[--tth11-r:170px] group-focus-visible/torch:[--tth11-r:60em] pointer-coarse:[--tth11-r:60em] motion-reduce:transition-none">MIDNIGHT<br>ATLAS</span>
</a>
<a href="#tth11-top" class="inline-flex min-h-11 items-center gap-2 rounded-full bg-tth11-acc px-5 text-sm font-bold text-tth11-bg no-underline transition-[translate,box-shadow] duration-300 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_-8px_var(--color-tth11-acc)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tth11-acc">Reserve a walk <span aria-hidden="true">→</span></a>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth11-mut">Sweep the cursor across the letters — the photo lives inside the glyphs; a radial <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">mask-image</code> at <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">var(--tth11-x) var(--tth11-y)</code> is the torch. <kbd class="rounded-[5px] border border-b-2 border-white/15 bg-tth11-chip px-1.5 py-0.5 font-tth11-mono text-[11px]">Tab</kbd> floods it fully lit.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}
```
## JavaScript
```js
(function () {
var wrap = document.querySelector('[data-tth11-torch]');
if (!wrap) return;
wrap.addEventListener('pointermove', function (e) {
var r = wrap.getBoundingClientRect();
wrap.style.setProperty('--tth11-x', (e.clientX - r.left) + 'px');
wrap.style.setProperty('--tth11-y', (e.clientY - r.top) + 'px');
});
wrap.addEventListener('pointerleave', function () {
wrap.style.removeProperty('--tth11-x');
wrap.style.removeProperty('--tth11-y');
});
})();
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Spotlight Text Reveal on Mouse Hover
Source: https://codefronts.com/motion/tailwind-css-text-hover-effects/tailwind-spotlight-text-reveal-on-mouse-hover/
A night-photography headline where the cursor is a torch: a city photo lives inside the glyphs (bg-clip-text), hidden by a radial mask-image centred at var(--tth11-x) var(--tth11-y). A 12-line script writes the coordinates; Tailwind does everything else, including the typed radius that grows from 0 to 170px on hover.
## HTML
```html
<section class="tth-11 w-full min-h-svh grid place-items-center bg-tth11-bg bg-[radial-gradient(100%_80%_at_50%_100%,var(--color-tth11-glow),var(--color-tth11-bg)_65%)] px-5 py-14 font-tth11-sans text-tth11-ink" aria-label="Spotlight text reveal demo">
<div class="flex flex-col items-center gap-[clamp(18px,3.4vw,28px)] text-center">
<p class="text-xs font-bold uppercase tracking-[0.28em] text-tth11-mut">Night photography walks — booking winter 2026</p>
<a id="tth11-top" href="#tth11-top" data-tth11-torch class="group/torch relative inline-block rounded-md px-[0.12em] py-[0.1em] text-[clamp(52px,11.5vw,118px)] font-black leading-[1.02] tracking-[-0.02em] [font-stretch:115%] no-underline [--tth11-r:0px] focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-tth11-acc">
<span class="block text-tth11-bg [paint-order:stroke_fill] [-webkit-text-stroke:3px_color-mix(in_oklch,var(--color-tth11-ink)_45%,transparent)]">MIDNIGHT<br>ATLAS</span>
<span aria-hidden="true" style="--tth11-photo:url('https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?q=80&w=1600&auto=format&fit=crop')" class="absolute inset-0 block px-[0.12em] py-[0.1em] bg-[image:linear-gradient(oklch(0.5_0.1_260/0.35),oklch(0.5_0.1_260/0.35)),var(--tth11-photo),linear-gradient(120deg,var(--color-tth11-acc),oklch(0.6_0.18_300))] bg-cover bg-center bg-clip-text text-transparent [mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] [-webkit-mask-image:radial-gradient(circle_var(--tth11-r)_at_var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)] transition-[--tth11-r] duration-550 ease-[cubic-bezier(.3,.9,.2,1)] group-hover/torch:[--tth11-r:170px] group-focus-visible/torch:[--tth11-r:60em] pointer-coarse:[--tth11-r:60em] motion-reduce:transition-none">MIDNIGHT<br>ATLAS</span>
</a>
<a href="#tth11-top" class="inline-flex min-h-11 items-center gap-2 rounded-full bg-tth11-acc px-5 text-sm font-bold text-tth11-bg no-underline transition-[translate,box-shadow] duration-300 hover:-translate-y-0.5 hover:shadow-[0_10px_30px_-8px_var(--color-tth11-acc)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tth11-acc">Reserve a walk <span aria-hidden="true">→</span></a>
<p class="max-w-[56ch] text-[12.5px] leading-[1.7] text-tth11-mut">Sweep the cursor across the letters — the photo lives inside the glyphs; a radial <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">mask-image</code> at <code class="rounded bg-tth11-chip px-1.5 py-px font-tth11-mono text-[0.92em] text-tth11-acc">var(--tth11-x) var(--tth11-y)</code> is the torch. <kbd class="rounded-[5px] border border-b-2 border-white/15 bg-tth11-chip px-1.5 py-0.5 font-tth11-mono text-[11px]">Tab</kbd> floods it fully lit.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@property --tth11-r {
syntax: '<length>';
inherits: true;
initial-value: 0px;
}
@theme {
--color-tth11-bg: #0b0e16;
--color-tth11-bg: oklch(0.15 0.012 265);
--color-tth11-glow: #161a29;
--color-tth11-glow: oklch(0.2 0.025 270);
--color-tth11-chip: #1a1e2a;
--color-tth11-chip: oklch(0.23 0.015 265);
--color-tth11-ink: #eaedf3;
--color-tth11-ink: oklch(0.94 0.01 250);
--color-tth11-mut: #9aa0ae;
--color-tth11-mut: oklch(0.71 0.02 255);
--color-tth11-acc: #f0c14b;
--color-tth11-acc: oklch(0.83 0.14 85);
--font-tth11-sans: 'Archivo', system-ui, sans-serif;
--font-tth11-mono: 'JetBrains Mono', ui-monospace, monospace;
}
.tth-11 {
width: 100%;
min-height: 100svh;
}
```
## JavaScript
```js
(function () {
var wrap = document.querySelector('[data-tth11-torch]');
if (!wrap) return;
wrap.addEventListener('pointermove', function (e) {
var r = wrap.getBoundingClientRect();
wrap.style.setProperty('--tth11-x', (e.clientX - r.left) + 'px');
wrap.style.setProperty('--tth11-y', (e.clientY - r.top) + 'px');
});
wrap.addEventListener('pointerleave', function () {
wrap.style.removeProperty('--tth11-x');
wrap.style.removeProperty('--tth11-y');
});
})();
```How this works
Two layers, one mask. The base layer is the outlined word. Above it sits an identical, aria-hidden layer whose background is the photo, clipped to the glyphs. A radial mask hides everything outside a circle:
<span class="absolute inset-0 bg-[image:…,var(--tth11-photo)] bg-cover bg-clip-text
text-transparent [mask-image:radial-gradient(circle_var(--tth11-r)_at_
var(--tth11-x,50%)_var(--tth11-y,50%),#000_38%,transparent_100%)]
transition-[--tth11-r] group-hover/torch:[--tth11-r:170px]">The script only measures. On pointermove it writes the pointer's position, relative to the link, into --tth11-x/--tth11-y on the link; the layer inherits them. On leave it removes them so the mask recentres.
Keyboard focus sets the radius to 60em — the whole word floods with light — so focus users get the full reveal instead of a torch they can't aim.
Make it yours
- Beam size: change
170px; softer edge: lower the#000_38%stop. - Different photo: edit the
--tth11-photoURL in the inline style. - No JS: drop the script and the mask stays centred — a hover-to-reveal iris.
Gotchas — read before shipping
- The radius must be a registered
<length>(@property) or the beam pops open instead of growing. - Safari still needs
-webkit-mask-image; both are declared. - Hotlinked photos can fail — the tinted gradient under the photo keeps the word visible.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 120+ | 16.4+ | 128+ | 120+ |
Unprefixed mask-image is Chrome 120+; Safari uses the prefixed copy.