<x-obscured>

A “shimmer spoiler” Web Component that obscures inline text with animated WebGL noise.
Works in React, Vue, Angular — you name it — even plain HTML!

Examples

Click any spoiler to reveal it.

The password is hunter2 — don’t share it.

The winner of the competition was definitely not who you'd expect.

In the final chapter, the protagonist discovers that the mysterious stranger was their long-lost sibling, and the treasure map actually led to their childhood home all along, which was a twist nobody saw coming. It was quite the ending.

Name: John Doe · Phone: +1 (555) 012-3456 · SSN: 123-45-6789

The respondent chose A, but the correct answer was B.

Slow & sparse: gentle secret · Fast & dense: chaotic secret

This paragraph is orange, so the spoiler matches the color automatically.

The treasure was buried under the old oak tree behind the library, three paces north of the stone bench, exactly where the map said it would be. Nobody would have guessed.

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