npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vault66-crt-effect

v3.1.1

Published

A customizable CRT (retro monitor) visual effect for React, Vue, and Web Components

Downloads

4,286

Readme

vault66-crt-effect

Live playground and documentation →

npm npm downloads npm total downloads

A CRT screen effect you wrap around any content: scanlines, sweep line, glow, flicker, glitch, screen curvature, glare, and static. Ships for React, Vue, and as a framework-agnostic Web Component (so it also works in Angular, plain HTML, Astro, Svelte, or anything else that runs in a browser).


CRT Effect Demo

Installation

npm install vault66-crt-effect
pnpm add vault66-crt-effect
yarn add vault66-crt-effect
bun add vault66-crt-effect

Use it with your framework

Same effect, same props everywhere — only the import and the syntax change. Presets get you a full look in one line; every individual prop is listed in Props.

React

import CRTEffect from "vault66-crt-effect";
import "vault66-crt-effect/style.css";

export default function App() {
  return (
    <CRTEffect preset="fallout">
      <div style={{ padding: 20, fontSize: 24 }}>Welcome to the Wasteland!</div>
    </CRTEffect>
  );
}

Vue

<script setup>
import CRTEffect from "vault66-crt-effect/vue";
import "vault66-crt-effect/style.css";
</script>

<template>
  <CRTEffect preset="fallout">
    <div style="padding: 20px; font-size: 24px">Welcome to the Wasteland!</div>
  </CRTEffect>
</template>

Web Component

Import once to register the <crt-effect> element, then use it anywhere — no CSS import needed, the component carries its own styles in a shadow root. Props become attributes: booleans are bare (fill), everything else is kebab-case (sweep-duration="5").

<script type="module">
  import "vault66-crt-effect/element";
</script>

<crt-effect preset="fallout">
  <div style="padding: 20px; font-size: 24px">Welcome to the Wasteland!</div>
</crt-effect>

Angular uses the same element — just add CUSTOM_ELEMENTS_SCHEMA to your component/module so the compiler accepts the custom tag (otherwise you'll hit NG8001), and import "vault66-crt-effect/element" once:

import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "vault66-crt-effect/element";

@Component({
  selector: "app-root",
  standalone: true,
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `<crt-effect preset="fallout">…</crt-effect>`,
})
export class AppComponent {}

Props

Every prop works the same across React, Vue, and the Web Component. Start from a preset and override whatever you want, or set props from scratch.

| Prop | Type | Default | Purpose | | --------------------- | ---------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | preset | "fallout" \| "dos" \| "cyberpunk" \| "arcade" \| "commodore64" \| "apple2" \| "vt100" \| "minimal" | undefined | Apply a complete preset configuration. Individual props can override preset values. See Presets below | | enabled | boolean | true | Enables or disables the entire CRT effect | | sweepDuration | number | 10 | Duration in seconds for the vertical sweep line animation | | sweepThickness | number | 10 | Height (thickness in pixels) of the sweep line | | sweepStyle | "classic" \| "soft" | "classic" | Style of the vertical sweep line: "classic" is a sharp black line, "soft" is a blurred shadow effect | | scanlineOpacity | number (0 to 1) | 0.2 | Opacity of the scanlines | | scanlineThickness | number | 2 | Thickness of each scanline in pixels | | scanlineGap | number | 3 | Gap between scanlines in pixels | | scanlineColor | string | "rgba(91, 179, 135, 0.2)" | Custom hex, RGB, or RGBA scanline color (used only if theme is "custom"; alpha is controlled by scanlineOpacity) | | enableScanlines | boolean | true | Shows or hides the scanlines overlay | | scanlineOrientation | "horizontal" \| "vertical" | "horizontal" | Orientation of the scanlines: "horizontal" renders lines from top to bottom, "vertical" renders lines from left to right | | enableSweep | boolean | true | Shows or hides the vertical sweep line animation | | theme | "green" \| "amber" \| "blue" \| "custom" | "green" | Predefined scanline color themes (overrides scanlineColor unless custom is used) | | enableGlow | boolean | false | Enables outer glow effect around the container | | glowColor | string | "rgba(0, 255, 128, 0.3)" | Color of the outer glow | | enableEdgeGlow | boolean | false | Enables inset glow effect around edges | | edgeGlowColor | string | "rgba(0, 255, 128, 0.2)" | Color of the inset edge glow | | edgeGlowSize | number | 30 | Size in pixels of the inset edge glow (box-shadow inset size) | | enableFlicker | boolean | false | Enables subtle flicker animation for CRT realism | | flickerIntensity | "low" \| "medium" \| "high" \| number | 0.08 | Flicker depth: preset string or custom number (0-1) where 0=no flicker, 1=max brightness variance | | flickerSpeed | "low" \| "medium" \| "high" \| number | 0.8 | Flicker animation speed: preset string or custom number in seconds. Lower values = faster flicker | | enableGlitch | boolean | false | Enables shaking/interference glitch animation | | glitchIntensity | "low" \| "medium" \| "high" \| number | 0.6 | Glitch distance: preset string or custom number (0-1) where 0=no movement, 1=max shake amount | | glitchSpeed | "low" \| "medium" \| "high" \| number | 0.6 | Glitch animation speed: preset string or custom number in seconds. Lower values = faster glitch | | enableVignette | boolean | false | Enables a subtle edge-darkening vignette overlay | | vignetteIntensity | number (0 to 1) | 0.4 | Controls vignette darkness at the edges | | enableCurvature | boolean | false | Enables a curved-glass overlay: a soft corner highlight plus darkened, rounded screen edges | | curvatureIntensity | number (0 to 1) | 0.5 | Strength of the curved-glass edge darkening | | enableGlare | boolean | false | Enables a broad, soft diagonal glass-reflection sheen across the screen | | glareIntensity | number (0 to 1) | 0.18 | Brightness of the glare/reflection sheen | | enableNoise | boolean | false | Enables an animated RF static/snow overlay generated from SVG fractal noise | | noiseOpacity | number (0 to 1) | 0.15 | Opacity of the static/snow overlay | | glitchChromatic | boolean | false | Adds animated red/cyan chromatic aberration to the glitch (requires enableGlitch) | | tintText | boolean | false | Recolors the wrapped content to a phosphor tint (derived from theme) with a soft glow. Children with their own explicit color keep it | | textColor | string | undefined | Overrides the phosphor tint color used when tintText is on. Any CSS color | | sweepColor | string | undefined | Gives the sweep line a bright, colored glow instead of the default dark refresh bar. Any CSS color | | fill | boolean | false | Stretches the effect to fill its parent's full width and height instead of sizing to its content. See Full-screen layouts | | children | content | — | Content rendered inside the effect: React children, the Vue default slot, or slotted DOM in the Web Component |

In the Web Component, prop names are kebab-case attributes: enableGlowenable-glow, sweepDurationsweep-duration="5", and booleans are set by presence (fill, enable-flicker).

Presets

Eight ready-made monitor looks. Use one as-is, or as a starting point and override individual props.

| Preset | Look | | ------------- | --------------------------------------------------------------------------------------------- | | fallout | Green Vault-Tec phosphor terminal — medium scanlines, sweep, subtle edge glow, gentle flicker | | dos | Amber IBM/Hercules monitor — clean scanlines, no sweep or glow | | cyberpunk | Purple/magenta neon — heavy outer + edge glow, fast sweep, flicker, glitch | | arcade | Bright saturated green — thick scanlines, fast sweep, strong glow | | commodore64 | Periwinkle 8-bit home computer — chunky scanlines, subtle flicker | | apple2 | Green Apple II — tight scanlines, clean (no sweep or glow) | | vt100 | Pale green DEC terminal — minimal scanlines, no sweep or glow | | minimal | Barely-there — subtle scanlines + light vignette only |

// Use a preset as-is
<CRTEffect preset="arcade">
  <YourContent />
</CRTEffect>

// Override specific preset values
<CRTEffect preset="fallout" sweepDuration={5} enableFlicker={false}>
  <YourContent />
</CRTEffect>

Customization

Start from a preset and change a few values, or build the whole look from individual props. A few common patterns (React syntax; the props are identical in Vue and the Web Component):

// Custom scanline color and orientation
<CRTEffect theme="custom" scanlineColor="#ff6400" scanlineOpacity={0.3} scanlineOrientation="vertical">
  <YourContent />
</CRTEffect>

// Fine-tune flicker and glitch with numbers
<CRTEffect
  enableFlicker
  flickerIntensity={0.05}  // subtle brightness variance (0-1)
  flickerSpeed={2}         // slow flicker (seconds)
  enableGlitch
  glitchIntensity={0.3}    // gentle shake (0-1)
  glitchSpeed={1.5}        // medium speed (seconds)
>
  <YourContent />
</CRTEffect>

// Or use the "low" / "medium" / "high" shortcuts
<CRTEffect enableFlicker flickerIntensity="low" enableGlitch glitchIntensity="high">
  <YourContent />
</CRTEffect>

Full-screen layouts

By default the wrapper sizes to its content — good for cards, panels, and inline blocks. When you want the effect to cover a whole region or the full viewport, add fill so the wrapper stretches to its parent (and the content stretches with it):

// The parent needs a real height — here, the full viewport
<div style={{ width: "100vw", height: "100vh" }}>
  <CRTEffect preset="fallout" fill>
    <YourApp />
  </CRTEffect>
</div>

fill fills the parent, so the parent must have a resolved height (100vh, a fixed px, or 100% inherited down the chain).

Building your own integration

If your framework isn't React or Vue and you'd rather not use the Web Component, the core is exported separately. computeCrt(options) takes the same props and hands back everything needed to render the effect onto your own markup — no framework attached. It's exactly what the React and Vue wrappers are built on.

It returns four things:

const { enabled, wrapper, inner, overlays } = computeCrt({ preset: "fallout" });
  • enabledfalse when the effect is turned off; render your content untouched.
  • wrapper{ className, style } for the outer element.
  • inner{ className, style } for the element that holds your content.
  • overlays — an array of class names, one per overlay layer.

The markup contract is: a wrapper element containing an inner element (your content goes in there), followed by one empty overlay div per entry in overlays:

<div class="{wrapper.className}" style="{wrapper.style}">
  <div class="{inner.className}" style="{inner.style}">…your content…</div>
  <!-- one sibling div per overlay class -->
  <div class="crt-vignette"></div>
</div>

One catch when applying the styles by hand: the style bag contains both normal CSS properties (filter, flexDirection) and CSS custom properties (--scanline-color-rgb). Custom properties have to be set with setProperty, not by assigning to el.style. Here's a complete vanilla-DOM renderer that handles it:

import { computeCrt } from "vault66-crt-effect/core";
import "vault66-crt-effect/style.css";

function applyStyle(el, style) {
  for (const [key, value] of Object.entries(style)) {
    if (key.startsWith("--")) el.style.setProperty(key, String(value));
    else el.style[key] = value;
  }
}

// Wrap any element in the CRT effect and return the new root element.
function crt(content, options) {
  const { enabled, wrapper, inner, overlays } = computeCrt(options);
  if (!enabled) return content; // effect off — hand content back as-is

  const root = document.createElement("div");
  root.className = wrapper.className;
  applyStyle(root, wrapper.style);

  const innerEl = document.createElement("div");
  innerEl.className = inner.className;
  if (inner.style) applyStyle(innerEl, inner.style);
  innerEl.append(content);
  root.append(innerEl);

  for (const cls of overlays) {
    const layer = document.createElement("div");
    layer.className = cls;
    root.append(layer);
  }
  return root;
}

const screen = crt(myContent, { preset: "fallout" });
document.body.append(screen);

Reduced motion

If the system has "Reduce Motion" enabled, animated layers (sweep, flicker, glitch, static) turn themselves off automatically, while layers like scanlines and glow stay visible. Nothing to configure.

License

MIT — see LICENSE for details.