Catalog npm
Back to packageRELEASE DETAILS

0.1.1

npm

@-3-/veil

A React cover that hides its content until the pointer scratches it away.

canvasparticlesreactrevealscratchscratch-card
Published20 Oct 2026
Direct dependencies6
Transitive dependenciesNot calculated

README

Current package documentation

@-3-/veil

A React cover that hides its content until the pointer scratches it away. Cleared pixels fly off as particles: floating, falling, blown by the wind, or burning to ash.

Try every texture and effect in the demo →

npm install @-3-/veil
# or
pnpm add @-3-/veil
# or
yarn add @-3-/veil

Usage

import { Veil } from "@-3-/veil";

export const Prize = () => (
  <Veil texture="scratch-card" effect="ash">
    <div style={{ width: 300, height: 120 }}>You won!</div>
  </Veil>
);

The veil takes the size of its content, so give the content the size you want covered.

Reset and progress

import { Veil, type VeilHandle } from "@-3-/veil";
import { useRef, useState } from "react";

export const Card = () => {
  const veilRef = useRef<VeilHandle>(null);
  const [percent, setPercent] = useState(0);

  return (
    <>
      <Veil ref={veilRef} onReveal={setPercent} revealThreshold={80}>
        <button type="button">Claim</button>
      </Veil>
      <p>{percent}% revealed</p>
      <button type="button" onClick={() => veilRef.current?.reset()}>
        Cover again
      </button>
    </>
  );
};

Props

PropTypeDefaultDescription
childrenReactNode—The content to cover.
textureVeilTexture"noise"How the cover looks. Changing it covers everything again.
effectVeilEffect"float"How cleared pixels leave the cover. Changing it covers everything again.
windDirectionVeilWindDirection"right"Which way the wind effect blows. Ignored by other effects.
brushSizenumber50Width of the cleared trail, in pixels.
disabledbooleanfalseStops the pointer from clearing anything. What is cleared stays cleared.
revealThresholdnumber50Percent of the cover that must be cleared before the content can be focused, clicked or read by screen readers. 0 makes it usable from the start; 100 waits until every pixel is cleared.
onReveal(percent: number) => void—Called with the cleared share of the cover, in whole percents (0–100), each time it changes.
classNamestring—Class for the outer element.
styleCSSProperties—Style for the outer element.
refRef<VeilHandle>—ref.current.reset() covers everything again.

Textures

plain · noise · mosaic · scratch-card · grain · scanlines · gradient · dither

noise, mosaic, grain and scanlines keep moving; the others are still.

Effects

EffectCleared pixels…
floatdrift up
sandfall, faster and faster
scatterburst outward from the stroke
dissolvefade where they were
windblow away in windDirection
snowdrift down, swaying
sparkleflicker as they rise a little
ashburn: embers rise from a glowing edge, the rest crumbles to ash

Wind directions

up-left · up · up-right · left · any · right · down-left · down · down-right

any blows each pixel its own way.

Behavior

  • Covered content is inert. Until revealThreshold percent is cleared, the content can't be focused, clicked or read by screen readers, so it can't be reached without scratching. After that, clicks still only pass through cleared pixels.
  • Reduced motion. When the user prefers reduced motion, cleared pixels just fade in place and moving textures hold still.
  • Touch. Dragging a finger over the veil scratches it instead of scrolling the page.
  • Resizing. When the content or the window changes the veil's size, it is covered again from scratch.
  • Particles. Pixels fly up to 56px past the cover (112px above it), drawn on a layer that overflows the veil, but only as far as the visible part of the page or its scrolling container reaches, so it never adds a scrollbar. At most 20,000 move at once; past that, cleared pixels just vanish.
  • Server rendering. The component is marked "use client" and touches browser APIs only after mounting, so it works in Next.js (App and Pages Router) and other server-rendered React apps.

Requirements

  • React 18 or 19
  • A browser with canvas and ResizeObserver (every current browser)

The package ships ES modules only.

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 7

Native requirements
6 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
react
Environment
{
  "local_name": "react",
  "alias": false,
  "peer_metadata": null
}
^19.3.0development
tsdown
Environment
{
  "local_name": "tsdown",
  "alias": false,
  "peer_metadata": null
}
^0.23.1development
publint
Environment
{
  "local_name": "publint",
  "alias": false,
  "peer_metadata": null
}
^0.3.25development
typescript
Environment
{
  "local_name": "typescript",
  "alias": false,
  "peer_metadata": null
}
^7.0.2development
@types/react
Environment
{
  "local_name": "@types/react",
  "alias": false,
  "peer_metadata": null
}
^19.3.0development
@arethetypeswrong/cli
Environment
{
  "local_name": "@arethetypeswrong/cli",
  "alias": false,
  "peer_metadata": null
}
^0.18.5development
react
Environment
{
  "local_name": "react",
  "alias": false,
  "peer_metadata": null
}
^18.0.0 || ^19.0.0peer

Distribution files

1 collected
Distribution 1

Source distribution

Source file
Checksums from source
{
  "shasum": "d64a3edb0fc844c312f24cfef0ddd8b3ca91f10a",
  "tarball": "https://registry.npmjs.org/@-3-/veil/-/veil-0.1.1.tgz",
  "fileCount": 5,
  "integrity": "sha512-RPFzrfpAj841xjjf4VN9cAcciJyzcTPDJXmZ2IbzU9KmMzb/F+bi6+11uNCH/p8Vg+jDSxfFMIpI1IKOO7Q8pw==",
  "signatures": [
    {
      "sig": "MEQCIHdzFzRPTPL3SWKpPsCKCiRHjK+a3D9EL/0ZGystg2/uAiADAhcSqMIt+5ds5uOCCiSSwnYHI9i+IfilwyuWeF77yQ==",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    },
    {
      "sig": "MEUCIQCZrx9e3m9Qn+24oiYw2AbFKYM9nq/QhGN098GIgn4pOgIgFMndltS/IP+0f3s0lCl+Qm6KCMA6sqhasQhTO26Glk0=",
      "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
    }
  ],
  "unpackedSize": 23943
}

Repository

PENDING
charmingjae/veil

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:48 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:4cdada43507a1ec51b27f9ebe8578f3113287522ff7519fa8eb9970086ee25ec

Other collected versions

0.1.220 Oct0.1.020 Oct0.0.0-stage20 OctView all collected versions →