vault66-crt-effect
Version:
A customizable CRT (retro monitor) visual effect for React, Vue, and Web Components
394 lines (393 loc) • 9.54 kB
JavaScript
const ne = {
/**
* FALLOUT
*/
fallout: {
theme: "green",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.25,
scanlineThickness: 2,
scanlineGap: 3,
enableSweep: !0,
sweepDuration: 12,
sweepThickness: 6,
sweepStyle: "classic",
sweepColor: "rgba(91, 179, 135, 0.5)",
enableGlow: !1,
enableEdgeGlow: !0,
edgeGlowColor: "rgba(91, 179, 135, 0.5)",
edgeGlowSize: 40,
enableFlicker: !0,
flickerIntensity: 0.05,
flickerSpeed: 1.5,
enableVignette: !0,
vignetteIntensity: 0.3,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.6,
enableNoise: !0,
noiseOpacity: 0.2
},
/**
* DOS - Classic DOS/Hercules monitor
*/
dos: {
theme: "custom",
scanlineColor: "rgba(255, 100, 0, 0.3)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.2,
scanlineThickness: 2,
scanlineGap: 4,
enableSweep: !1,
enableGlow: !1,
enableEdgeGlow: !1,
enableFlicker: !1,
enableVignette: !0,
vignetteIntensity: 0.25,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.55
},
/**
* CYBERPUNK
*/
cyberpunk: {
theme: "custom",
scanlineColor: "rgba(255, 0, 255, 0.3)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.35,
scanlineThickness: 2,
scanlineGap: 2,
enableSweep: !0,
sweepDuration: 5,
sweepThickness: 8,
sweepStyle: "classic",
sweepColor: "rgba(255, 0, 200, 0.5)",
enableGlow: !0,
glowColor: "rgba(255, 0, 200, 0.5)",
enableEdgeGlow: !0,
edgeGlowColor: "rgba(200, 0, 255, 0.6)",
edgeGlowSize: 50,
enableFlicker: !0,
flickerIntensity: 0.08,
flickerSpeed: 0.8,
enableVignette: !0,
vignetteIntensity: 0.4,
enableGlitch: !0,
glitchIntensity: 0.3,
glitchSpeed: 1,
glitchChromatic: !0,
enableCurvature: !0,
curvatureIntensity: 0.7,
enableGlare: !0,
glareIntensity: 0.25,
enableNoise: !0,
noiseOpacity: 0.18
},
/**
* COMMODORE 64 - 8-bit computer
*/
commodore64: {
theme: "custom",
scanlineColor: "rgba(160, 160, 255, 0.35)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.35,
scanlineThickness: 3,
scanlineGap: 2,
enableSweep: !0,
sweepDuration: 10,
sweepThickness: 6,
sweepStyle: "classic",
sweepColor: "rgba(160, 160, 255, 0.5)",
enableGlow: !1,
enableEdgeGlow: !1,
enableFlicker: !0,
flickerIntensity: 0.05,
flickerSpeed: 1.5,
enableVignette: !0,
vignetteIntensity: 0.35,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.6,
enableNoise: !0,
noiseOpacity: 0.15
},
/**
* APPLE II - Vintage Apple computer terminal
*/
apple2: {
theme: "custom",
scanlineColor: "rgba(120, 220, 80, 0.3)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.3,
scanlineThickness: 1,
scanlineGap: 2,
enableSweep: !1,
enableGlow: !1,
enableEdgeGlow: !1,
enableFlicker: !1,
enableVignette: !0,
vignetteIntensity: 0.2,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.55
},
/**
* ARCADE - Retro arcade cabinet monitor
*/
arcade: {
theme: "custom",
scanlineColor: "rgba(0, 255, 100, 0.4)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.4,
scanlineThickness: 3,
scanlineGap: 3,
enableSweep: !0,
sweepDuration: 4,
sweepThickness: 8,
sweepStyle: "classic",
sweepColor: "rgba(0, 255, 100, 0.5)",
enableGlow: !0,
glowColor: "rgba(0, 255, 100, 0.5)",
enableEdgeGlow: !0,
edgeGlowColor: "rgba(0, 255, 100, 0.6)",
edgeGlowSize: 45,
enableFlicker: !0,
flickerIntensity: 0.08,
flickerSpeed: 0.8,
enableVignette: !0,
vignetteIntensity: 0.45,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.7,
enableGlare: !0,
glareIntensity: 0.3
},
/**
* VT100 - Classic DEC terminal
*/
vt100: {
theme: "custom",
scanlineColor: "rgba(220, 255, 235, 0.2)",
tintText: !0,
enableScanlines: !0,
scanlineOpacity: 0.15,
scanlineThickness: 2,
scanlineGap: 4,
enableSweep: !1,
enableGlow: !1,
enableEdgeGlow: !1,
enableFlicker: !1,
enableVignette: !0,
vignetteIntensity: 0.15,
enableGlitch: !1,
enableCurvature: !0,
curvatureIntensity: 0.45
},
/**
* MINIMAL - Subtle CRT effect
*/
minimal: {
theme: "green",
enableScanlines: !0,
scanlineOpacity: 0.1,
scanlineThickness: 1,
scanlineGap: 4,
enableSweep: !1,
enableGlow: !1,
enableEdgeGlow: !1,
enableFlicker: !1,
enableVignette: !0,
vignetteIntensity: 0.2,
enableGlitch: !1
}
}, te = {
enabled: !0,
sweepDuration: 10,
sweepThickness: 10,
sweepStyle: "classic",
scanlineOpacity: 0.2,
scanlineColor: "rgba(91, 179, 135, 0.2)",
scanlineThickness: 2,
scanlineGap: 3,
enableScanlines: !0,
enableSweep: !0,
theme: "green",
enableGlow: !1,
glowColor: "rgba(0, 255, 128, 0.3)",
enableEdgeGlow: !1,
edgeGlowColor: "rgba(0, 255, 128, 0.2)",
edgeGlowSize: 30,
enableFlicker: !1,
scanlineOrientation: "horizontal",
glitchIntensity: 1,
glitchSpeed: 0.6,
flickerIntensity: 0.08,
flickerSpeed: 0.8,
enableGlitch: !1,
enableVignette: !1,
vignetteIntensity: 0.4,
enableCurvature: !1,
curvatureIntensity: 0.5,
enableGlare: !1,
glareIntensity: 0.18,
enableNoise: !1,
noiseOpacity: 0.15,
glitchChromatic: !1,
tintText: !1,
textColor: void 0,
sweepColor: void 0,
fill: !1
};
function h(e) {
const n = {};
for (const i in e) {
const a = e[i];
a !== void 0 && (n[i] = a);
}
return n;
}
function le(e) {
const n = e.trim(), i = n.match(/^#([\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i);
if (i) {
const t = i[1];
return (t.length <= 4 ? t.slice(0, 3).split("").map((s) => s + s) : [t.slice(0, 2), t.slice(2, 4), t.slice(4, 6)]).map((s) => Number.parseInt(s, 16)).join(", ");
}
const a = n.match(/^rgba?\((.*)\)$/i);
if (a) {
const t = a[1].split("/")[0].trim().split(/[\s,]+/).filter(Boolean).slice(0, 3);
if (t.length === 3 && t.every((r) => /^\d*\.?\d+%?$/.test(r)))
return t.join(", ");
}
return "91, 179, 135";
}
const d = {
green: "91, 179, 135",
// Classic CRT green
amber: "255, 200, 100",
// Vintage amber monitor
blue: "100, 200, 255"
// Retro blue terminal
};
function y(e, n) {
return typeof e == "number" ? e : n[e];
}
function G(e, n) {
return typeof e == "number" ? `${e}s` : n[e];
}
function ie(e = {}) {
const { preset: n, ...i } = e, a = n ? ne[n] : {}, t = { ...te, ...h(a), ...h(i) }, {
enabled: r,
sweepDuration: s,
sweepThickness: m,
sweepStyle: k,
scanlineOpacity: v,
scanlineColor: C,
scanlineThickness: S,
scanlineGap: I,
enableScanlines: x,
enableSweep: o,
theme: u,
enableGlow: T,
glowColor: O,
enableEdgeGlow: b,
edgeGlowColor: V,
edgeGlowSize: E,
enableFlicker: F,
scanlineOrientation: N,
glitchIntensity: $,
glitchSpeed: z,
flickerIntensity: D,
flickerSpeed: B,
enableGlitch: p,
enableVignette: j,
vignetteIntensity: M,
enableCurvature: R,
curvatureIntensity: H,
enableGlare: q,
glareIntensity: A,
enableNoise: J,
noiseOpacity: K,
glitchChromatic: L,
tintText: g,
textColor: P,
sweepColor: c,
fill: w
} = t, f = u !== "custom" ? d[u] ?? d.green : le(C), Q = P ?? `rgb(${f})`, U = y(D, {
low: 0.05,
medium: 0.08,
high: 0.12
}), W = G(B, {
low: "1.5s",
medium: "0.8s",
high: "0.4s"
}), X = y($, {
low: 0.3,
medium: 0.6,
high: 0.9
}), Y = G(z, {
low: "1s",
medium: "0.6s",
high: "0.3s"
}), Z = [
"crt-effect-wrapper",
x && "scanlines-on",
o && (k === "classic" ? "sweep-on" : "sweep-soft"),
o && c && "sweep-colored",
b && "edge-glow-on",
F && "flicker-on"
].filter(Boolean).join(" "), l = {
position: "relative",
overflow: "hidden",
"--sweep-duration": `${s}s`,
"--sweep-thickness": `${m}px`,
"--scanline-opacity": v,
"--scanline-color-rgb": f,
"--scanline-thickness": `${S}px`,
"--scanline-gap": `${I}px`,
"--glow-color": O,
"--edge-glow-color": V,
"--edge-glow-size": `${E}px`,
"--scanline-gradient-direction": N === "horizontal" ? "to bottom" : "to right",
"--glitch-speed": Y,
"--glitch-intensity": X,
"--flicker-speed": W,
"--flicker-intensity": U,
"--vignette-intensity": M,
"--curvature-intensity": H,
"--glare-intensity": A,
"--noise-opacity": K
};
g && (l["--crt-text-color"] = Q), c && (l["--sweep-color"] = c), T && (l.filter = "drop-shadow(0 0 6px var(--glow-color)) drop-shadow(0 0 12px var(--glow-color)) drop-shadow(0 0 20px var(--glow-color))"), w && (l.width = "100%", l.height = "100%", l.display = "flex", l.flexDirection = "column");
const _ = [
"crt-inner",
p && "glitch-on",
p && L && "chromatic-on",
g && "tint-text-on"
].filter(Boolean).join(" "), ee = [
R && "crt-curvature",
J && "crt-noise",
q && "crt-glare",
b && "crt-edge-glow",
j && "crt-vignette"
].filter(Boolean);
return {
enabled: r,
wrapper: { className: Z, style: l },
inner: {
className: _,
style: w ? { display: "flex", flexDirection: "column" } : void 0
},
overlays: ee
};
}
export {
ie as computeCrt,
ne as presets
};