@oalacea/chaosui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/bin/cli.js +216 -0
  2. package/components/backgrounds/glow-orbs/glow-orbs.module.css +31 -0
  3. package/components/backgrounds/glow-orbs/index.tsx +87 -0
  4. package/components/backgrounds/light-beams/index.tsx +80 -0
  5. package/components/backgrounds/light-beams/light-beams.module.css +27 -0
  6. package/components/backgrounds/noise-canvas/index.tsx +113 -0
  7. package/components/backgrounds/noise-canvas/noise-canvas.module.css +8 -0
  8. package/components/backgrounds/particle-field/index.tsx +81 -0
  9. package/components/backgrounds/particle-field/particle-field.module.css +31 -0
  10. package/components/buttons/chaos-button/chaos-button.module.css +173 -0
  11. package/components/buttons/chaos-button/index.tsx +60 -0
  12. package/components/buttons/glitch-button/glitch-button.module.css +197 -0
  13. package/components/buttons/glitch-button/index.tsx +53 -0
  14. package/components/effects/cursor-follower/cursor-follower.module.css +50 -0
  15. package/components/effects/cursor-follower/index.tsx +83 -0
  16. package/components/effects/screen-distortion/index.tsx +54 -0
  17. package/components/effects/screen-distortion/screen-distortion.module.css +127 -0
  18. package/components/effects/warning-tape/index.tsx +64 -0
  19. package/components/effects/warning-tape/warning-tape.module.css +29 -0
  20. package/components/glow-orbs/glow-orbs.module.css +31 -0
  21. package/components/glow-orbs/index.tsx +87 -0
  22. package/components/light-beams/index.tsx +80 -0
  23. package/components/light-beams/light-beams.module.css +27 -0
  24. package/components/noise-canvas/index.tsx +113 -0
  25. package/components/noise-canvas/noise-canvas.module.css +8 -0
  26. package/components/overlays/noise-overlay/index.tsx +56 -0
  27. package/components/overlays/noise-overlay/noise-overlay.module.css +20 -0
  28. package/components/overlays/scanlines/index.tsx +61 -0
  29. package/components/overlays/scanlines/scanlines.module.css +16 -0
  30. package/components/overlays/static-flicker/index.tsx +51 -0
  31. package/components/overlays/static-flicker/static-flicker.module.css +27 -0
  32. package/components/overlays/vignette/index.tsx +58 -0
  33. package/components/overlays/vignette/vignette.module.css +7 -0
  34. package/components/package.json +13 -0
  35. package/components/particle-field/index.tsx +81 -0
  36. package/components/particle-field/particle-field.module.css +31 -0
  37. package/components/text/distortion-text/distortion-text.module.css +100 -0
  38. package/components/text/distortion-text/index.tsx +53 -0
  39. package/components/text/falling-text/falling-text.module.css +57 -0
  40. package/components/text/falling-text/index.tsx +61 -0
  41. package/components/text/flicker-text/flicker-text.module.css +91 -0
  42. package/components/text/flicker-text/index.tsx +48 -0
  43. package/components/text/glitch-text/glitch-text.module.css +142 -0
  44. package/components/text/glitch-text/index.tsx +53 -0
  45. package/package.json +38 -0
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './scanlines.module.css';
5
+
6
+ export interface ScanlinesProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Line opacity (0-1) */
8
+ opacity?: number;
9
+ /** Line thickness in pixels */
10
+ lineWidth?: number;
11
+ /** Gap between lines in pixels */
12
+ gap?: number;
13
+ /** Line color */
14
+ color?: string;
15
+ /** Enable flicker animation */
16
+ flicker?: boolean;
17
+ /** Fixed position (covers viewport) or absolute (covers parent) */
18
+ position?: 'fixed' | 'absolute';
19
+ }
20
+
21
+ export const Scanlines = forwardRef<HTMLDivElement, ScanlinesProps>(
22
+ (
23
+ {
24
+ opacity = 0.1,
25
+ lineWidth = 1,
26
+ gap = 2,
27
+ color = '#000000',
28
+ flicker = false,
29
+ position = 'fixed',
30
+ className,
31
+ style,
32
+ ...props
33
+ },
34
+ ref
35
+ ) => {
36
+ return (
37
+ <div
38
+ ref={ref}
39
+ className={`${styles.scanlines} ${flicker ? styles.flicker : ''} ${className || ''}`}
40
+ style={{
41
+ position,
42
+ opacity,
43
+ background: `repeating-linear-gradient(
44
+ 0deg,
45
+ ${color},
46
+ ${color} ${lineWidth}px,
47
+ transparent ${lineWidth}px,
48
+ transparent ${lineWidth + gap}px
49
+ )`,
50
+ ...style,
51
+ }}
52
+ aria-hidden="true"
53
+ {...props}
54
+ />
55
+ );
56
+ }
57
+ );
58
+
59
+ Scanlines.displayName = 'Scanlines';
60
+
61
+ export default Scanlines;
@@ -0,0 +1,16 @@
1
+ .scanlines {
2
+ inset: 0;
3
+ width: 100%;
4
+ height: 100%;
5
+ pointer-events: none;
6
+ z-index: 9998;
7
+ }
8
+
9
+ .flicker {
10
+ animation: scanline-flicker 0.1s infinite;
11
+ }
12
+
13
+ @keyframes scanline-flicker {
14
+ 0%, 100% { opacity: 0.1; }
15
+ 50% { opacity: 0.15; }
16
+ }
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './static-flicker.module.css';
5
+
6
+ export interface StaticFlickerProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Noise opacity (0-1) */
8
+ opacity?: number;
9
+ /** Flicker speed: slow, normal, fast */
10
+ speed?: 'slow' | 'normal' | 'fast';
11
+ /** Noise frequency */
12
+ frequency?: number;
13
+ /** Fixed or absolute positioning */
14
+ position?: 'fixed' | 'absolute';
15
+ }
16
+
17
+ export const StaticFlicker = forwardRef<HTMLDivElement, StaticFlickerProps>(
18
+ (
19
+ {
20
+ opacity = 0.03,
21
+ speed = 'normal',
22
+ frequency = 0.9,
23
+ position = 'fixed',
24
+ className,
25
+ style,
26
+ ...props
27
+ },
28
+ ref
29
+ ) => {
30
+ const noiseSvg = `url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='${frequency}' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E")`;
31
+
32
+ return (
33
+ <div
34
+ ref={ref}
35
+ className={`${styles.static} ${styles[speed]} ${className || ''}`}
36
+ style={{
37
+ position,
38
+ opacity,
39
+ backgroundImage: noiseSvg,
40
+ ...style,
41
+ }}
42
+ aria-hidden="true"
43
+ {...props}
44
+ />
45
+ );
46
+ }
47
+ );
48
+
49
+ StaticFlicker.displayName = 'StaticFlicker';
50
+
51
+ export default StaticFlicker;
@@ -0,0 +1,27 @@
1
+ .static {
2
+ inset: 0;
3
+ width: 100%;
4
+ height: 100%;
5
+ pointer-events: none;
6
+ z-index: 9999;
7
+ }
8
+
9
+ .slow {
10
+ animation: flicker 0.2s steps(8) infinite;
11
+ }
12
+
13
+ .normal {
14
+ animation: flicker 0.1s steps(5) infinite;
15
+ }
16
+
17
+ .fast {
18
+ animation: flicker 0.05s steps(3) infinite;
19
+ }
20
+
21
+ @keyframes flicker {
22
+ 0%, 100% { opacity: 0.02; }
23
+ 20% { opacity: 0.04; }
24
+ 40% { opacity: 0.02; }
25
+ 60% { opacity: 0.03; }
26
+ 80% { opacity: 0.025; }
27
+ }
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './vignette.module.css';
5
+
6
+ export interface VignetteProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Vignette intensity (0-1) */
8
+ intensity?: number;
9
+ /** Vignette color */
10
+ color?: string;
11
+ /** Vignette spread (0-1, how far the effect extends) */
12
+ spread?: number;
13
+ /** Fixed position (covers viewport) or absolute (covers parent) */
14
+ position?: 'fixed' | 'absolute';
15
+ }
16
+
17
+ export const Vignette = forwardRef<HTMLDivElement, VignetteProps>(
18
+ (
19
+ {
20
+ intensity = 0.8,
21
+ color = '#000000',
22
+ spread = 0.5,
23
+ position = 'fixed',
24
+ className,
25
+ style,
26
+ ...props
27
+ },
28
+ ref
29
+ ) => {
30
+ // Convert hex to rgba for gradient
31
+ const hexToRgba = (hex: string, alpha: number) => {
32
+ const r = parseInt(hex.slice(1, 3), 16);
33
+ const g = parseInt(hex.slice(3, 5), 16);
34
+ const b = parseInt(hex.slice(5, 7), 16);
35
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
36
+ };
37
+
38
+ const innerStop = Math.max(0, (1 - spread) * 100);
39
+
40
+ return (
41
+ <div
42
+ ref={ref}
43
+ className={`${styles.vignette} ${className || ''}`}
44
+ style={{
45
+ position,
46
+ background: `radial-gradient(ellipse at center, transparent ${innerStop}%, ${hexToRgba(color, intensity)} 100%)`,
47
+ ...style,
48
+ }}
49
+ aria-hidden="true"
50
+ {...props}
51
+ />
52
+ );
53
+ }
54
+ );
55
+
56
+ Vignette.displayName = 'Vignette';
57
+
58
+ export default Vignette;
@@ -0,0 +1,7 @@
1
+ .vignette {
2
+ inset: 0;
3
+ width: 100%;
4
+ height: 100%;
5
+ pointer-events: none;
6
+ z-index: 9997;
7
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "@chaos/components",
3
+ "version": "0.1.0",
4
+ "description": "Glitch, noise, and distortion UI components",
5
+ "type": "module",
6
+ "exports": {
7
+ "./text/*": "./text/*/index.tsx",
8
+ "./overlays/*": "./overlays/*/index.tsx",
9
+ "./buttons/*": "./buttons/*/index.tsx",
10
+ "./effects/*": "./effects/*/index.tsx",
11
+ "./backgrounds/*": "./backgrounds/*/index.tsx"
12
+ }
13
+ }
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes, useMemo } from 'react';
4
+ import styles from './particle-field.module.css';
5
+
6
+ export interface ParticleFieldProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Number of particles */
8
+ count?: number;
9
+ /** Particle color */
10
+ color?: string;
11
+ /** Particle size range [min, max] in pixels */
12
+ sizeRange?: [number, number];
13
+ /** Animation duration range [min, max] in seconds */
14
+ durationRange?: [number, number];
15
+ /** Particle opacity */
16
+ opacity?: number;
17
+ /** Fixed or absolute positioning */
18
+ position?: 'fixed' | 'absolute';
19
+ }
20
+
21
+ export const ParticleField = forwardRef<HTMLDivElement, ParticleFieldProps>(
22
+ (
23
+ {
24
+ count = 50,
25
+ color = '#ffffff',
26
+ sizeRange = [1, 3],
27
+ durationRange = [10, 20],
28
+ opacity = 0.5,
29
+ position = 'fixed',
30
+ className,
31
+ style,
32
+ ...props
33
+ },
34
+ ref
35
+ ) => {
36
+ const particles = useMemo(() => {
37
+ return Array.from({ length: count }, (_, i) => {
38
+ const size = sizeRange[0] + Math.random() * (sizeRange[1] - sizeRange[0]);
39
+ const duration = durationRange[0] + Math.random() * (durationRange[1] - durationRange[0]);
40
+ const delay = Math.random() * -duration;
41
+ const startX = Math.random() * 100;
42
+ const startY = Math.random() * 100;
43
+ const drift = (Math.random() - 0.5) * 100;
44
+
45
+ return { id: i, size, duration, delay, startX, startY, drift };
46
+ });
47
+ }, [count, sizeRange, durationRange]);
48
+
49
+ return (
50
+ <div
51
+ ref={ref}
52
+ className={`${styles.container} ${className || ''}`}
53
+ style={{ position, ...style }}
54
+ aria-hidden="true"
55
+ {...props}
56
+ >
57
+ {particles.map((p) => (
58
+ <div
59
+ key={p.id}
60
+ className={styles.particle}
61
+ style={{
62
+ width: p.size,
63
+ height: p.size,
64
+ backgroundColor: color,
65
+ opacity,
66
+ left: `${p.startX}%`,
67
+ top: `${p.startY}%`,
68
+ animationDuration: `${p.duration}s`,
69
+ animationDelay: `${p.delay}s`,
70
+ '--drift': `${p.drift}px`,
71
+ } as React.CSSProperties}
72
+ />
73
+ ))}
74
+ </div>
75
+ );
76
+ }
77
+ );
78
+
79
+ ParticleField.displayName = 'ParticleField';
80
+
81
+ export default ParticleField;
@@ -0,0 +1,31 @@
1
+ .container {
2
+ inset: 0;
3
+ width: 100%;
4
+ height: 100%;
5
+ overflow: hidden;
6
+ pointer-events: none;
7
+ z-index: 1;
8
+ }
9
+
10
+ .particle {
11
+ position: absolute;
12
+ border-radius: 50%;
13
+ animation: drift linear infinite;
14
+ }
15
+
16
+ @keyframes drift {
17
+ 0% {
18
+ transform: translate(0, 0);
19
+ opacity: 0;
20
+ }
21
+ 10% {
22
+ opacity: var(--opacity, 0.5);
23
+ }
24
+ 90% {
25
+ opacity: var(--opacity, 0.5);
26
+ }
27
+ 100% {
28
+ transform: translate(var(--drift, 50px), -100vh);
29
+ opacity: 0;
30
+ }
31
+ }
@@ -0,0 +1,100 @@
1
+ .distortion {
2
+ display: inline-block;
3
+ }
4
+
5
+ /* WAVE */
6
+ .wave {
7
+ animation: wave var(--duration, 2s) ease-in-out infinite;
8
+ }
9
+
10
+ .wave.subtle { --wave-amount: 2px; }
11
+ .wave.medium { --wave-amount: 5px; }
12
+ .wave.intense { --wave-amount: 10px; }
13
+
14
+ @keyframes wave {
15
+ 0%, 100% {
16
+ transform: translateY(0) skewX(0);
17
+ }
18
+ 25% {
19
+ transform: translateY(calc(var(--wave-amount) * -1)) skewX(-2deg);
20
+ }
21
+ 50% {
22
+ transform: translateY(0) skewX(0);
23
+ }
24
+ 75% {
25
+ transform: translateY(var(--wave-amount)) skewX(2deg);
26
+ }
27
+ }
28
+
29
+ /* SHAKE */
30
+ .shake {
31
+ animation: shake var(--duration, 0.5s) linear infinite;
32
+ }
33
+
34
+ .shake.subtle { --shake-amount: 1px; }
35
+ .shake.medium { --shake-amount: 3px; }
36
+ .shake.intense { --shake-amount: 6px; }
37
+
38
+ @keyframes shake {
39
+ 0%, 100% { transform: translate(0); }
40
+ 10% { transform: translate(calc(var(--shake-amount) * -1), var(--shake-amount)); }
41
+ 20% { transform: translate(var(--shake-amount), calc(var(--shake-amount) * -1)); }
42
+ 30% { transform: translate(calc(var(--shake-amount) * -1), calc(var(--shake-amount) * -1)); }
43
+ 40% { transform: translate(var(--shake-amount), var(--shake-amount)); }
44
+ 50% { transform: translate(calc(var(--shake-amount) * -1), 0); }
45
+ 60% { transform: translate(var(--shake-amount), 0); }
46
+ 70% { transform: translate(0, var(--shake-amount)); }
47
+ 80% { transform: translate(0, calc(var(--shake-amount) * -1)); }
48
+ 90% { transform: translate(var(--shake-amount), var(--shake-amount)); }
49
+ }
50
+
51
+ /* SKEW */
52
+ .skew {
53
+ animation: skew var(--duration, 3s) ease-in-out infinite;
54
+ }
55
+
56
+ .skew.subtle { --skew-amount: 3deg; }
57
+ .skew.medium { --skew-amount: 8deg; }
58
+ .skew.intense { --skew-amount: 15deg; }
59
+
60
+ @keyframes skew {
61
+ 0%, 100% { transform: skewX(0) skewY(0); }
62
+ 25% { transform: skewX(var(--skew-amount)) skewY(calc(var(--skew-amount) * 0.5)); }
63
+ 50% { transform: skewX(0) skewY(0); }
64
+ 75% { transform: skewX(calc(var(--skew-amount) * -1)) skewY(calc(var(--skew-amount) * -0.5)); }
65
+ }
66
+
67
+ /* BLUR */
68
+ .blur {
69
+ animation: blur var(--duration, 2s) ease-in-out infinite;
70
+ }
71
+
72
+ .blur.subtle { --blur-amount: 1px; }
73
+ .blur.medium { --blur-amount: 3px; }
74
+ .blur.intense { --blur-amount: 6px; }
75
+
76
+ @keyframes blur {
77
+ 0%, 100% { filter: blur(0); }
78
+ 50% { filter: blur(var(--blur-amount)); }
79
+ }
80
+
81
+ /* SPEEDS */
82
+ .slow { --duration: 4s; }
83
+ .normal { --duration: 2s; }
84
+ .fast { --duration: 0.8s; }
85
+
86
+ .shake.slow { --duration: 1s; }
87
+ .shake.normal { --duration: 0.5s; }
88
+ .shake.fast { --duration: 0.2s; }
89
+
90
+ /* HOVER ONLY */
91
+ .hoverOnly {
92
+ animation: none;
93
+ transform: none;
94
+ filter: none;
95
+ }
96
+
97
+ .hoverOnly.wave:hover { animation: wave var(--duration, 2s) ease-in-out infinite; }
98
+ .hoverOnly.shake:hover { animation: shake var(--duration, 0.5s) linear infinite; }
99
+ .hoverOnly.skew:hover { animation: skew var(--duration, 3s) ease-in-out infinite; }
100
+ .hoverOnly.blur:hover { animation: blur var(--duration, 2s) ease-in-out infinite; }
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './distortion-text.module.css';
5
+
6
+ export interface DistortionTextProps extends HTMLAttributes<HTMLSpanElement> {
7
+ /** The text to display */
8
+ children: string;
9
+ /** Distortion type */
10
+ type?: 'wave' | 'shake' | 'skew' | 'blur';
11
+ /** Animation speed: slow, normal, fast */
12
+ speed?: 'slow' | 'normal' | 'fast';
13
+ /** Distortion intensity */
14
+ intensity?: 'subtle' | 'medium' | 'intense';
15
+ /** Only animate on hover */
16
+ hoverOnly?: boolean;
17
+ }
18
+
19
+ export const DistortionText = forwardRef<HTMLSpanElement, DistortionTextProps>(
20
+ (
21
+ {
22
+ children,
23
+ type = 'wave',
24
+ speed = 'normal',
25
+ intensity = 'medium',
26
+ hoverOnly = false,
27
+ className,
28
+ ...props
29
+ },
30
+ ref
31
+ ) => {
32
+ return (
33
+ <span
34
+ ref={ref}
35
+ className={`
36
+ ${styles.distortion}
37
+ ${styles[type]}
38
+ ${styles[speed]}
39
+ ${styles[intensity]}
40
+ ${hoverOnly ? styles.hoverOnly : ''}
41
+ ${className || ''}
42
+ `}
43
+ {...props}
44
+ >
45
+ {children}
46
+ </span>
47
+ );
48
+ }
49
+ );
50
+
51
+ DistortionText.displayName = 'DistortionText';
52
+
53
+ export default DistortionText;
@@ -0,0 +1,57 @@
1
+ .container {
2
+ display: inline-flex;
3
+ overflow: hidden;
4
+ }
5
+
6
+ .letter {
7
+ display: inline-block;
8
+ opacity: 0;
9
+ animation-fill-mode: forwards;
10
+ animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
11
+ }
12
+
13
+ .down {
14
+ animation-name: fall-down;
15
+ }
16
+
17
+ .up {
18
+ animation-name: fall-up;
19
+ }
20
+
21
+ .loop {
22
+ animation-iteration-count: infinite;
23
+ }
24
+
25
+ @keyframes fall-down {
26
+ 0% {
27
+ opacity: 0;
28
+ transform: translateY(-100%) rotate(-10deg);
29
+ }
30
+ 20% {
31
+ opacity: 1;
32
+ }
33
+ 80% {
34
+ opacity: 1;
35
+ }
36
+ 100% {
37
+ opacity: 0;
38
+ transform: translateY(100%) rotate(10deg);
39
+ }
40
+ }
41
+
42
+ @keyframes fall-up {
43
+ 0% {
44
+ opacity: 0;
45
+ transform: translateY(100%) rotate(10deg);
46
+ }
47
+ 20% {
48
+ opacity: 1;
49
+ }
50
+ 80% {
51
+ opacity: 1;
52
+ }
53
+ 100% {
54
+ opacity: 0;
55
+ transform: translateY(-100%) rotate(-10deg);
56
+ }
57
+ }
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, HTMLAttributes } from 'react';
4
+ import styles from './falling-text.module.css';
5
+
6
+ export interface FallingTextProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** Text to display falling */
8
+ children: string;
9
+ /** Fall duration in seconds */
10
+ duration?: number;
11
+ /** Stagger delay between letters in ms */
12
+ stagger?: number;
13
+ /** Loop the animation */
14
+ loop?: boolean;
15
+ /** Fall direction */
16
+ direction?: 'down' | 'up';
17
+ }
18
+
19
+ export const FallingText = forwardRef<HTMLDivElement, FallingTextProps>(
20
+ (
21
+ {
22
+ children,
23
+ duration = 2,
24
+ stagger = 100,
25
+ loop = true,
26
+ direction = 'down',
27
+ className,
28
+ style,
29
+ ...props
30
+ },
31
+ ref
32
+ ) => {
33
+ const letters = children.split('');
34
+
35
+ return (
36
+ <div
37
+ ref={ref}
38
+ className={`${styles.container} ${className || ''}`}
39
+ style={style}
40
+ {...props}
41
+ >
42
+ {letters.map((letter, i) => (
43
+ <span
44
+ key={i}
45
+ className={`${styles.letter} ${styles[direction]} ${loop ? styles.loop : ''}`}
46
+ style={{
47
+ animationDuration: `${duration}s`,
48
+ animationDelay: `${i * stagger}ms`,
49
+ }}
50
+ >
51
+ {letter === ' ' ? '\u00A0' : letter}
52
+ </span>
53
+ ))}
54
+ </div>
55
+ );
56
+ }
57
+ );
58
+
59
+ FallingText.displayName = 'FallingText';
60
+
61
+ export default FallingText;