<x-obscured>
A “shimmer spoiler” Web Component that obscures inline text with animated WebGL noise.
Works in React, Vue, Angular — you name it — even
- Supports multi-line and text wrapping
- Framework-agnostic, zero dependencies
- Click-to-reveal with programmatic API
- Customizable density, speed, and color
Examples
Click any spoiler to reveal it.
The password is
The winner of the competition was
In the final chapter,
Name:
The respondent chose
Slow & sparse:
This paragraph is orange, so the spoiler
Installing
npm install x-obscured
Or use a CDN:
<script type="module" src="https://unpkg.com/x-obscured"></script>
Usage
<script type="module">
import "x-obscured";
</script>
<p>
The winner was <x-obscured>definitely not who you'd expect</x-obscured>
— to everyone's surprise.
</p>
Just wrap any inline text. The component preserves layout and renders animated noise over it.
React TLDR
import "x-obscured";
import type { ReactNode } from "react";
import { useEffect, useRef } from "react";
export default function Obscured({
children,
revealed = false,
}: {
children: ReactNode;
revealed?: boolean;
}) {
return (
<x-obscured {...(revealed ? { revealed: "revealed" } : {})}>
{children}
</x-obscured>
);
}
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
revealed |
boolean | — | Set to anything to reveal |
density |
number | 1 |
Noise density multiplier |
speed |
number | 1 |
Animation speed multiplier |
color |
string | — | Override color (inherits from parent) |
expand |
string | .25em |
Expands the render area beyond the text bounds by the given amount in any CSS units |
<x-obscured density="2" speed="0.5" color="#e87c5b" expand="4px">secret</x-obscured>
JavaScript API
const el = document.querySelector("x-obscured");
el.reveal(); // reveal the content
el.obscure(); // obscure the content
el.toggle(); // toggle between revealed/obscured
Events
| Event | Fired when |
|---|---|
reveal |
Content becomes visible |
obscure |
Content becomes obscured |
How it works
The text stays in the DOM but is rendered transparent. A <canvas> is overlaid on top, and a GPU shader draws animated particles that obscure the content. The component figures out where each line of text is and only draws noise in those areas. Everything runs on the GPU, so it’s fast and smooth.
Tuning
import { XObscured } from "x-obscured";
// Component's layout gets automatically updated on resize, mutation, and font load.
// However, as a failsafe it also forces layout update every 2 seconds.
// This number can be tweaked by setting this constant:
// Default: 2000
XObscured.MEASURE_INTERVAL_MS = 5000;
Browser support
Requires WebGL 1.0. Works in all modern browsers (Chrome, Firefox, Safari, Edge).
License
MIT