From 08d27bf72e9befc4136eafee320e9cbb1e5d0546 Mon Sep 17 00:00:00 2001 From: Agnik47 <140933190+Agnik47@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:36:01 +0530 Subject: [PATCH 1/2] fix(docs): correct 48 prop-table defaults that disagreed with component sources The `propData` tables rendered on the component docs pages had drifted from the actual defaults declared in each component. 48 entries across 16 components documented a value the code does not use, so anyone reading the table (or pasting it into an AI assistant) got code that behaves differently from what the docs promised. Each corrected value is taken from the JS-CSS source, which is the variant the docs page renders. Worst case was TextPressure, whose table was shifted by one row: `textColor` showed `stroke`'s default, `strokeColor` showed `textColor`'s, and `className` showed `strokeColor`'s. Refs #1058 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019zcJiZJ3Y6DoLvLT2gKLfC --- src/demo/Animations/ClickSparkDemo.jsx | 8 ++++---- src/demo/Animations/MetaBallsDemo.jsx | 2 +- src/demo/Animations/RibbonsDemo.jsx | 8 ++++---- src/demo/Animations/StarBorderDemo.jsx | 2 +- src/demo/Backgrounds/FerrofluidDemo.jsx | 8 ++++---- src/demo/Backgrounds/LightRaysDemo.jsx | 8 ++++---- src/demo/Backgrounds/LightfallDemo.jsx | 14 +++++++------- src/demo/Backgrounds/LiquidChromeDemo.jsx | 8 ++++---- src/demo/Backgrounds/PixelBlastDemo.jsx | 4 ++-- src/demo/Backgrounds/PlasmaDemo.jsx | 4 ++-- src/demo/Backgrounds/RippleGridDemo.jsx | 4 ++-- src/demo/Backgrounds/SideRaysDemo.jsx | 14 +++++++------- src/demo/Components/PillNavDemo.jsx | 2 +- src/demo/Components/StaggeredMenuDemo.jsx | 2 +- src/demo/TextAnimations/TextPressureDemo.jsx | 8 ++++---- 15 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/demo/Animations/ClickSparkDemo.jsx b/src/demo/Animations/ClickSparkDemo.jsx index 59f04c0f1..a6d34c015 100644 --- a/src/demo/Animations/ClickSparkDemo.jsx +++ b/src/demo/Animations/ClickSparkDemo.jsx @@ -43,19 +43,19 @@ const ClickSparkDemo = () => { { name: 'sparkColor', type: 'string', - default: "'#f00'", + default: "'#fff'", description: 'Color of each spark line.' }, { name: 'sparkSize', type: 'number', - default: 30, + default: 10, description: 'Initial length of each spark line.' }, { name: 'sparkRadius', type: 'number', - default: 30, + default: 15, description: 'How far sparks travel from the click center.' }, { @@ -67,7 +67,7 @@ const ClickSparkDemo = () => { { name: 'duration', type: 'number', - default: 660, + default: 400, description: 'Animation duration in milliseconds.' }, { diff --git a/src/demo/Animations/MetaBallsDemo.jsx b/src/demo/Animations/MetaBallsDemo.jsx index 79e77243f..03c21c75d 100644 --- a/src/demo/Animations/MetaBallsDemo.jsx +++ b/src/demo/Animations/MetaBallsDemo.jsx @@ -107,7 +107,7 @@ const MetaBallsDemo = () => { { name: 'cursorBallColor', type: 'string', - default: '#ff0000', + default: '#ffffff', description: 'Color of the cursor ball.' } ], diff --git a/src/demo/Animations/RibbonsDemo.jsx b/src/demo/Animations/RibbonsDemo.jsx index cd9ee7d51..0102893c1 100644 --- a/src/demo/Animations/RibbonsDemo.jsx +++ b/src/demo/Animations/RibbonsDemo.jsx @@ -59,7 +59,7 @@ const RibbonsDemo = () => { { name: 'offsetFactor', type: 'number', - default: '0.02', + default: '0.05', description: 'A factor to horizontally offset the starting positions of the ribbons.' }, { @@ -77,19 +77,19 @@ const RibbonsDemo = () => { { name: 'speedMultiplier', type: 'number', - default: '0.5', + default: '0.6', description: 'Multiplier that adjusts how fast trailing points interpolate towards the head.' }, { name: 'enableFade', type: 'boolean', - default: 'true', + default: 'false', description: 'If true, a fade effect is applied along the length of the ribbon.' }, { name: 'enableShaderEffect', type: 'boolean', - default: 'true', + default: 'false', description: 'If true, an additional sine-wave shader effect is applied to the ribbons.' }, { diff --git a/src/demo/Animations/StarBorderDemo.jsx b/src/demo/Animations/StarBorderDemo.jsx index febd93e05..a18d5be1c 100644 --- a/src/demo/Animations/StarBorderDemo.jsx +++ b/src/demo/Animations/StarBorderDemo.jsx @@ -64,7 +64,7 @@ const StarBorderDemo = () => { { name: 'thickness', type: 'number', - default: '3', + default: '1', description: 'Controls the thickness of the star border effect.' }, { diff --git a/src/demo/Backgrounds/FerrofluidDemo.jsx b/src/demo/Backgrounds/FerrofluidDemo.jsx index d307e718c..195f673bc 100644 --- a/src/demo/Backgrounds/FerrofluidDemo.jsx +++ b/src/demo/Backgrounds/FerrofluidDemo.jsx @@ -90,7 +90,7 @@ const FerrofluidDemo = () => { { name: 'scale', type: 'number', - default: '1', + default: '1.6', description: 'Overall feature size. Higher values zoom in for larger, fewer blobs.' }, { @@ -114,13 +114,13 @@ const FerrofluidDemo = () => { { name: 'sharpness', type: 'number', - default: '3', + default: '2.5', description: 'Contrast of the rim highlights. Higher values give crisper, thinner edges.' }, { name: 'shimmer', type: 'number', - default: '1', + default: '1.5', description: 'Amount of fine grainy break-up applied to the rim. 0 = smooth lines.' }, { @@ -156,7 +156,7 @@ const FerrofluidDemo = () => { { name: 'mouseRadius', type: 'number', - default: '0.3', + default: '0.35', description: 'Falloff radius of the magnetic cursor spike.' }, { diff --git a/src/demo/Backgrounds/LightRaysDemo.jsx b/src/demo/Backgrounds/LightRaysDemo.jsx index 792a6ebe2..654528867 100644 --- a/src/demo/Backgrounds/LightRaysDemo.jsx +++ b/src/demo/Backgrounds/LightRaysDemo.jsx @@ -83,13 +83,13 @@ const LightRaysDemo = () => { { name: 'lightSpread', type: 'number', - default: '0.5', + default: '1', description: 'How wide the light rays spread. Lower values = tighter rays, higher values = wider spread' }, { name: 'rayLength', type: 'number', - default: '1.0', + default: '2', description: 'Maximum length/reach of the rays' }, { @@ -113,13 +113,13 @@ const LightRaysDemo = () => { { name: 'followMouse', type: 'boolean', - default: 'false', + default: 'true', description: 'Make rays rotate towards the mouse cursor' }, { name: 'mouseInfluence', type: 'number', - default: '0.5', + default: '0.1', description: 'How much mouse affects rays (0-1)' }, { diff --git a/src/demo/Backgrounds/LightfallDemo.jsx b/src/demo/Backgrounds/LightfallDemo.jsx index 29550dfe9..6239d4fcc 100644 --- a/src/demo/Backgrounds/LightfallDemo.jsx +++ b/src/demo/Backgrounds/LightfallDemo.jsx @@ -80,13 +80,13 @@ const LightfallDemo = () => { { name: 'speed', type: 'number', - default: '1', + default: '0.5', description: 'Multiplier for how fast the light streaks fall.' }, { name: 'streakCount', type: 'number', - default: '8', + default: '2', description: 'Number of streak layers rendered per cell (1–16). Higher = busier.' }, { @@ -110,7 +110,7 @@ const LightfallDemo = () => { { name: 'density', type: 'number', - default: '1', + default: '0.6', description: 'Vertical frequency of streaks. Higher values pack more streaks into view.' }, { @@ -122,13 +122,13 @@ const LightfallDemo = () => { { name: 'zoom', type: 'number', - default: '2', + default: '3', description: 'Field of view into the tunnel. Higher values zoom further in.' }, { name: 'backgroundGlow', type: 'number', - default: '1', + default: '0.5', description: 'Intensity of the ambient background glow.' }, { @@ -146,13 +146,13 @@ const LightfallDemo = () => { { name: 'mouseStrength', type: 'number', - default: '1', + default: '0.5', description: 'Intensity of the cursor light.' }, { name: 'mouseRadius', type: 'number', - default: '0.6', + default: '1', description: 'Falloff radius of the cursor light.' }, { diff --git a/src/demo/Backgrounds/LiquidChromeDemo.jsx b/src/demo/Backgrounds/LiquidChromeDemo.jsx index 399c51b71..5a5870c0b 100644 --- a/src/demo/Backgrounds/LiquidChromeDemo.jsx +++ b/src/demo/Backgrounds/LiquidChromeDemo.jsx @@ -50,25 +50,25 @@ const LiquidChromeDemo = () => { { name: 'speed', type: 'number', - default: '1.0', + default: '0.2', description: 'Animation speed multiplier.' }, { name: 'amplitude', type: 'number', - default: '0.6', + default: '0.3', description: 'Amplitude of the distortion.' }, { name: 'frequencyX', type: 'number', - default: '2.5', + default: '3', description: 'Frequency modifier for the x distortion.' }, { name: 'frequencyY', type: 'number', - default: '1.5', + default: '3', description: 'Frequency modifier for the y distortion.' }, { diff --git a/src/demo/Backgrounds/PixelBlastDemo.jsx b/src/demo/Backgrounds/PixelBlastDemo.jsx index 7c2e699b4..789392113 100644 --- a/src/demo/Backgrounds/PixelBlastDemo.jsx +++ b/src/demo/Backgrounds/PixelBlastDemo.jsx @@ -61,7 +61,7 @@ const PixelBlastDemo = () => { { name: 'pixelSize', type: 'number', - default: '4', + default: '3', description: 'Base pixel size (auto scaled for DPI).' }, { @@ -145,7 +145,7 @@ const PixelBlastDemo = () => { { name: 'edgeFade', type: 'number', - default: '0.25', + default: '0.5', description: 'Edge fade distance (0-1).' }, { diff --git a/src/demo/Backgrounds/PlasmaDemo.jsx b/src/demo/Backgrounds/PlasmaDemo.jsx index e78830749..24891be38 100644 --- a/src/demo/Backgrounds/PlasmaDemo.jsx +++ b/src/demo/Backgrounds/PlasmaDemo.jsx @@ -71,7 +71,7 @@ const PlasmaDemo = () => { { name: 'mouseInteractive', type: 'boolean', - default: 'false', + default: 'true', description: 'Whether the plasma responds to mouse movement.' }, { @@ -91,7 +91,7 @@ const PlasmaDemo = () => { { name: 'targetFps', type: 'number', - default: '30', + default: '60', description: 'Target frame rate for the animation loop. Lower values reduce CPU/GPU load.' }, { diff --git a/src/demo/Backgrounds/RippleGridDemo.jsx b/src/demo/Backgrounds/RippleGridDemo.jsx index d85359540..5b8990df9 100644 --- a/src/demo/Backgrounds/RippleGridDemo.jsx +++ b/src/demo/Backgrounds/RippleGridDemo.jsx @@ -116,13 +116,13 @@ const RippleGridDemo = () => { { name: 'mouseInteraction', type: 'boolean', - default: 'false', + default: 'true', description: 'Enable mouse/touch interaction to create ripples.' }, { name: 'mouseInteractionRadius', type: 'number', - default: '0.8', + default: '1', description: 'Controls the radius of the mouse interaction effect.' } ], diff --git a/src/demo/Backgrounds/SideRaysDemo.jsx b/src/demo/Backgrounds/SideRaysDemo.jsx index d11b2c945..3961986bc 100644 --- a/src/demo/Backgrounds/SideRaysDemo.jsx +++ b/src/demo/Backgrounds/SideRaysDemo.jsx @@ -50,13 +50,13 @@ const SideRaysDemo = () => { { name: 'speed', type: 'number', - default: '1.0', + default: '2.5', description: 'Animation speed of the rays' }, { name: 'rayColor1', type: 'string', - default: '"#ffaa6e"', + default: '"#EAB308"', description: 'Color of the first ray layer in hex format' }, { @@ -68,13 +68,13 @@ const SideRaysDemo = () => { { name: 'intensity', type: 'number', - default: '1.0', + default: '2', description: 'Overall brightness of the rays' }, { name: 'spread', type: 'number', - default: '1.0', + default: '2', description: 'Angular width of the ray fan — higher values create a wider spread between the two ray layers' }, { @@ -92,19 +92,19 @@ const SideRaysDemo = () => { { name: 'saturation', type: 'number', - default: '1.0', + default: '1.5', description: 'Color saturation of the rays — 0 renders in grayscale, values above 1 boost color' }, { name: 'blend', type: 'number', - default: '0.78', + default: '0.75', description: 'Balance between the two ray layers — 0 is all ray 1, 1 is all ray 2' }, { name: 'falloff', type: 'number', - default: '2.0', + default: '1.6', description: 'How steeply brightness diminishes with distance from the source — higher = tighter glow' }, { diff --git a/src/demo/Components/PillNavDemo.jsx b/src/demo/Components/PillNavDemo.jsx index 4c78712e7..b2e865f68 100644 --- a/src/demo/Components/PillNavDemo.jsx +++ b/src/demo/Components/PillNavDemo.jsx @@ -100,7 +100,7 @@ const PillNavDemo = () => { { name: 'initialLoadAnimation', type: 'boolean', - default: 'false', + default: 'true', description: 'Enable initial load animation for logo scale and nav items reveal' } ], diff --git a/src/demo/Components/StaggeredMenuDemo.jsx b/src/demo/Components/StaggeredMenuDemo.jsx index 2abe39a64..4be39633e 100644 --- a/src/demo/Components/StaggeredMenuDemo.jsx +++ b/src/demo/Components/StaggeredMenuDemo.jsx @@ -78,7 +78,7 @@ const StaggeredMenuDemo = () => { { name: 'displaySocials', type: 'boolean', - default: 'false', + default: 'true', description: 'Whether to display the social links section.' }, { diff --git a/src/demo/TextAnimations/TextPressureDemo.jsx b/src/demo/TextAnimations/TextPressureDemo.jsx index edc88ac3b..cda787a5d 100644 --- a/src/demo/TextAnimations/TextPressureDemo.jsx +++ b/src/demo/TextAnimations/TextPressureDemo.jsx @@ -21,7 +21,7 @@ const propData = [ { name: 'text', type: 'string', - default: '"Hello!"', + default: '"Compressa"', description: 'Text content that will be displayed and animated.' }, { @@ -81,19 +81,19 @@ const propData = [ { name: 'textColor', type: 'string', - default: 'true', + default: '#FFFFFF', description: 'The fill color of the text' }, { name: 'strokeColor', type: 'string', - default: '#FFFFFF', + default: '#FF0000', description: 'The stroke color that will be applied to the text when "stroke" is set to true' }, { name: 'className', type: 'string', - default: '#FF0000', + default: '""', description: 'Additional class for styling the

wrapper.' }, { From e9e309f8b000bcf747cf1cdfc8da0ff9f456cbdf Mon Sep 17 00:00:00 2001 From: Agnik47 <140933190+Agnik47@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:36:23 +0530 Subject: [PATCH 2/2] fix(variants): align outlier default values so all 4 variants match CONTRIBUTING requires the 4 variants to stay in sync, but three props shipped a different default depending on which variant you installed. In each case 3 of the 4 variants agree and the documented default agrees with that majority, so the odd one out is corrected: - GlitchText `speed` JS-CSS 1 -> 0.5 - GlitchText `enableOnHover` JS-CSS true -> false - MetaBalls `enableTransparency` JS-CSS true -> false - SideRays `falloff` TS-TW 2.0 -> 1.6 GlitchText was the user-visible one: the JS-CSS variant glitched continuously while the other three only glitched on hover. The MetaBalls demo never passed `enableTransparency`, so it relied on the JS-CSS default. It now passes the prop explicitly, which keeps the rendered preview exactly as it is today. Registry items for the three affected variants are rebuilt to match. Two further splits are deliberately left alone because the intended value is not mine to pick - see the PR description. Refs #1058 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019zcJiZJ3Y6DoLvLT2gKLfC --- public/r/GlitchText-JS-CSS.json | 2 +- public/r/MetaBalls-JS-CSS.json | 2 +- public/r/SideRays-TS-TW.json | 2 +- src/content/Animations/MetaBalls/MetaBalls.jsx | 2 +- src/content/TextAnimations/GlitchText/GlitchText.jsx | 2 +- src/demo/Animations/MetaBallsDemo.jsx | 1 + src/ts-tailwind/Backgrounds/SideRays/SideRays.tsx | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/public/r/GlitchText-JS-CSS.json b/public/r/GlitchText-JS-CSS.json index 34da9cdfb..08d80c9d3 100644 --- a/public/r/GlitchText-JS-CSS.json +++ b/public/r/GlitchText-JS-CSS.json @@ -14,7 +14,7 @@ { "type": "registry:component", "path": "GlitchText.jsx", - "content": "import './GlitchText.css';\n\nconst GlitchText = ({ children, speed = 1, enableShadows = true, enableOnHover = true, className = '' }) => {\n const inlineStyles = {\n '--after-duration': `${speed * 3}s`,\n '--before-duration': `${speed * 2}s`,\n '--after-shadow': enableShadows ? '-5px 0 red' : 'none',\n '--before-shadow': enableShadows ? '5px 0 cyan' : 'none'\n };\n\n const hoverClass = enableOnHover ? 'enable-on-hover' : '';\n\n return (\n
\n {children}\n
\n );\n};\n\nexport default GlitchText;\n" + "content": "import './GlitchText.css';\n\nconst GlitchText = ({ children, speed = 0.5, enableShadows = true, enableOnHover = false, className = '' }) => {\n const inlineStyles = {\n '--after-duration': `${speed * 3}s`,\n '--before-duration': `${speed * 2}s`,\n '--after-shadow': enableShadows ? '-5px 0 red' : 'none',\n '--before-shadow': enableShadows ? '5px 0 cyan' : 'none'\n };\n\n const hoverClass = enableOnHover ? 'enable-on-hover' : '';\n\n return (\n
\n {children}\n
\n );\n};\n\nexport default GlitchText;\n" } ], "registryDependencies": [], diff --git a/public/r/MetaBalls-JS-CSS.json b/public/r/MetaBalls-JS-CSS.json index c05c3f509..1f7cc8351 100644 --- a/public/r/MetaBalls-JS-CSS.json +++ b/public/r/MetaBalls-JS-CSS.json @@ -14,7 +14,7 @@ { "type": "registry:component", "path": "MetaBalls.jsx", - "content": "import { useEffect, useRef } from 'react';\nimport { Renderer, Program, Mesh, Triangle, Transform, Vec3, Camera } from 'ogl';\n\nimport './MetaBalls.css';\n\nfunction parseHexColor(hex) {\n const c = hex.replace('#', '');\n const r = parseInt(c.substring(0, 2), 16) / 255;\n const g = parseInt(c.substring(2, 4), 16) / 255;\n const b = parseInt(c.substring(4, 6), 16) / 255;\n return [r, g, b];\n}\n\nfunction fract(x) {\n return x - Math.floor(x);\n}\n\nfunction hash31(p) {\n let r = [p * 0.1031, p * 0.103, p * 0.0973].map(fract);\n const r_yzx = [r[1], r[2], r[0]];\n const dotVal = r[0] * (r_yzx[0] + 33.33) + r[1] * (r_yzx[1] + 33.33) + r[2] * (r_yzx[2] + 33.33);\n for (let i = 0; i < 3; i++) {\n r[i] = fract(r[i] + dotVal);\n }\n return r;\n}\n\nfunction hash33(v) {\n let p = [v[0] * 0.1031, v[1] * 0.103, v[2] * 0.0973].map(fract);\n const p_yxz = [p[1], p[0], p[2]];\n const dotVal = p[0] * (p_yxz[0] + 33.33) + p[1] * (p_yxz[1] + 33.33) + p[2] * (p_yxz[2] + 33.33);\n for (let i = 0; i < 3; i++) {\n p[i] = fract(p[i] + dotVal);\n }\n const p_xxy = [p[0], p[0], p[1]];\n const p_yxx = [p[1], p[0], p[0]];\n const p_zyx = [p[2], p[1], p[0]];\n const result = [];\n for (let i = 0; i < 3; i++) {\n result[i] = fract((p_xxy[i] + p_yxx[i]) * p_zyx[i]);\n }\n return result;\n}\n\nconst vertex = `#version 300 es\nprecision highp float;\nlayout(location = 0) in vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst fragment = `#version 300 es\nprecision highp float;\nuniform vec3 iResolution;\nuniform float iTime;\nuniform vec3 iMouse;\nuniform vec3 iColor;\nuniform vec3 iCursorColor;\nuniform float iAnimationSize;\nuniform int iBallCount;\nuniform float iCursorBallSize;\nuniform vec3 iMetaBalls[50];\nuniform float iClumpFactor;\nuniform bool enableTransparency;\nout vec4 outColor;\nconst float PI = 3.14159265359;\n\nfloat getMetaBallValue(vec2 c, float r, vec2 p) {\n vec2 d = p - c;\n float dist2 = dot(d, d);\n return (r * r) / dist2;\n}\n\nvoid main() {\n vec2 fc = gl_FragCoord.xy;\n float scale = iAnimationSize / iResolution.y;\n vec2 coord = (fc - iResolution.xy * 0.5) * scale;\n vec2 mouseW = (iMouse.xy - iResolution.xy * 0.5) * scale;\n float m1 = 0.0;\n for (int i = 0; i < 50; i++) {\n if (i >= iBallCount) break;\n m1 += getMetaBallValue(iMetaBalls[i].xy, iMetaBalls[i].z, coord);\n }\n float m2 = getMetaBallValue(mouseW, iCursorBallSize, coord);\n float total = m1 + m2;\n float f = smoothstep(-1.0, 1.0, (total - 1.3) / min(1.0, fwidth(total)));\n vec3 cFinal = vec3(0.0);\n if (total > 0.0) {\n float alpha1 = m1 / total;\n float alpha2 = m2 / total;\n cFinal = iColor * alpha1 + iCursorColor * alpha2;\n }\n outColor = vec4(cFinal * f, enableTransparency ? f : 1.0);\n}\n`;\n\nconst MetaBalls = ({\n className = '',\n color = '#ffffff',\n speed = 0.3,\n enableMouseInteraction = true,\n hoverSmoothness = 0.05,\n animationSize = 30,\n ballCount = 15,\n clumpFactor = 1,\n cursorBallSize = 3,\n cursorBallColor = '#ffffff',\n enableTransparency = true\n}) => {\n const containerRef = useRef(null);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const dpr = 1;\n const renderer = new Renderer({ dpr, alpha: true, premultipliedAlpha: false });\n const gl = renderer.gl;\n gl.clearColor(0, 0, 0, enableTransparency ? 0 : 1);\n container.appendChild(gl.canvas);\n\n const camera = new Camera(gl, {\n left: -1,\n right: 1,\n top: 1,\n bottom: -1,\n near: 0.1,\n far: 10\n });\n camera.position.z = 1;\n\n const geometry = new Triangle(gl);\n const [r1, g1, b1] = parseHexColor(color);\n const [r2, g2, b2] = parseHexColor(cursorBallColor);\n\n const metaBallsUniform = [];\n for (let i = 0; i < 50; i++) {\n metaBallsUniform.push(new Vec3(0, 0, 0));\n }\n\n const program = new Program(gl, {\n vertex,\n fragment,\n uniforms: {\n iTime: { value: 0 },\n iResolution: { value: new Vec3(0, 0, 0) },\n iMouse: { value: new Vec3(0, 0, 0) },\n iColor: { value: new Vec3(r1, g1, b1) },\n iCursorColor: { value: new Vec3(r2, g2, b2) },\n iAnimationSize: { value: animationSize },\n iBallCount: { value: ballCount },\n iCursorBallSize: { value: cursorBallSize },\n iMetaBalls: { value: metaBallsUniform },\n iClumpFactor: { value: clumpFactor },\n enableTransparency: { value: enableTransparency }\n }\n });\n\n const mesh = new Mesh(gl, { geometry, program });\n const scene = new Transform();\n mesh.setParent(scene);\n\n const maxBalls = 50;\n const effectiveBallCount = Math.min(ballCount, maxBalls);\n const ballParams = [];\n for (let i = 0; i < effectiveBallCount; i++) {\n const idx = i + 1;\n const h1 = hash31(idx);\n const st = h1[0] * (2 * Math.PI);\n const dtFactor = 0.1 * Math.PI + h1[1] * (0.4 * Math.PI - 0.1 * Math.PI);\n const baseScale = 5.0 + h1[1] * (10.0 - 5.0);\n const h2 = hash33(h1);\n const toggle = Math.floor(h2[0] * 2.0);\n const radiusVal = 0.5 + h2[2] * (2.0 - 0.5);\n ballParams.push({ st, dtFactor, baseScale, toggle, radius: radiusVal });\n }\n\n const mouseBallPos = { x: 0, y: 0 };\n let pointerInside = false;\n let pointerX = 0;\n let pointerY = 0;\n\n function resize() {\n if (!container) return;\n const width = container.clientWidth;\n const height = container.clientHeight;\n renderer.setSize(width * dpr, height * dpr);\n gl.canvas.style.width = width + 'px';\n gl.canvas.style.height = height + 'px';\n program.uniforms.iResolution.value.set(gl.canvas.width, gl.canvas.height, 0);\n }\n window.addEventListener('resize', resize);\n resize();\n\n function onPointerMove(e) {\n if (!enableMouseInteraction) return;\n const rect = container.getBoundingClientRect();\n const px = e.clientX - rect.left;\n const py = e.clientY - rect.top;\n pointerX = (px / rect.width) * gl.canvas.width;\n pointerY = (1 - py / rect.height) * gl.canvas.height;\n }\n function onPointerEnter() {\n if (!enableMouseInteraction) return;\n pointerInside = true;\n }\n function onPointerLeave() {\n if (!enableMouseInteraction) return;\n pointerInside = false;\n }\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerenter', onPointerEnter);\n container.addEventListener('pointerleave', onPointerLeave);\n\n const startTime = performance.now();\n let animationFrameId;\n function update(t) {\n animationFrameId = requestAnimationFrame(update);\n const elapsed = (t - startTime) * 0.001;\n program.uniforms.iTime.value = elapsed;\n\n for (let i = 0; i < effectiveBallCount; i++) {\n const p = ballParams[i];\n const dt = elapsed * speed * p.dtFactor;\n const th = p.st + dt;\n const x = Math.cos(th);\n const y = Math.sin(th + dt * p.toggle);\n const posX = x * p.baseScale * clumpFactor;\n const posY = y * p.baseScale * clumpFactor;\n metaBallsUniform[i].set(posX, posY, p.radius);\n }\n\n let targetX, targetY;\n if (pointerInside) {\n targetX = pointerX;\n targetY = pointerY;\n } else {\n const cx = gl.canvas.width * 0.5;\n const cy = gl.canvas.height * 0.5;\n const rx = gl.canvas.width * 0.15;\n const ry = gl.canvas.height * 0.15;\n targetX = cx + Math.cos(elapsed * speed) * rx;\n targetY = cy + Math.sin(elapsed * speed) * ry;\n }\n mouseBallPos.x += (targetX - mouseBallPos.x) * hoverSmoothness;\n mouseBallPos.y += (targetY - mouseBallPos.y) * hoverSmoothness;\n program.uniforms.iMouse.value.set(mouseBallPos.x, mouseBallPos.y, 0);\n\n renderer.render({ scene, camera });\n }\n animationFrameId = requestAnimationFrame(update);\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n window.removeEventListener('resize', resize);\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerenter', onPointerEnter);\n container.removeEventListener('pointerleave', onPointerLeave);\n container.removeChild(gl.canvas);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n };\n }, [\n color,\n cursorBallColor,\n speed,\n enableMouseInteraction,\n hoverSmoothness,\n animationSize,\n ballCount,\n clumpFactor,\n cursorBallSize,\n enableTransparency\n ]);\n\n return
;\n};\n\nexport default MetaBalls;\n" + "content": "import { useEffect, useRef } from 'react';\nimport { Renderer, Program, Mesh, Triangle, Transform, Vec3, Camera } from 'ogl';\n\nimport './MetaBalls.css';\n\nfunction parseHexColor(hex) {\n const c = hex.replace('#', '');\n const r = parseInt(c.substring(0, 2), 16) / 255;\n const g = parseInt(c.substring(2, 4), 16) / 255;\n const b = parseInt(c.substring(4, 6), 16) / 255;\n return [r, g, b];\n}\n\nfunction fract(x) {\n return x - Math.floor(x);\n}\n\nfunction hash31(p) {\n let r = [p * 0.1031, p * 0.103, p * 0.0973].map(fract);\n const r_yzx = [r[1], r[2], r[0]];\n const dotVal = r[0] * (r_yzx[0] + 33.33) + r[1] * (r_yzx[1] + 33.33) + r[2] * (r_yzx[2] + 33.33);\n for (let i = 0; i < 3; i++) {\n r[i] = fract(r[i] + dotVal);\n }\n return r;\n}\n\nfunction hash33(v) {\n let p = [v[0] * 0.1031, v[1] * 0.103, v[2] * 0.0973].map(fract);\n const p_yxz = [p[1], p[0], p[2]];\n const dotVal = p[0] * (p_yxz[0] + 33.33) + p[1] * (p_yxz[1] + 33.33) + p[2] * (p_yxz[2] + 33.33);\n for (let i = 0; i < 3; i++) {\n p[i] = fract(p[i] + dotVal);\n }\n const p_xxy = [p[0], p[0], p[1]];\n const p_yxx = [p[1], p[0], p[0]];\n const p_zyx = [p[2], p[1], p[0]];\n const result = [];\n for (let i = 0; i < 3; i++) {\n result[i] = fract((p_xxy[i] + p_yxx[i]) * p_zyx[i]);\n }\n return result;\n}\n\nconst vertex = `#version 300 es\nprecision highp float;\nlayout(location = 0) in vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst fragment = `#version 300 es\nprecision highp float;\nuniform vec3 iResolution;\nuniform float iTime;\nuniform vec3 iMouse;\nuniform vec3 iColor;\nuniform vec3 iCursorColor;\nuniform float iAnimationSize;\nuniform int iBallCount;\nuniform float iCursorBallSize;\nuniform vec3 iMetaBalls[50];\nuniform float iClumpFactor;\nuniform bool enableTransparency;\nout vec4 outColor;\nconst float PI = 3.14159265359;\n\nfloat getMetaBallValue(vec2 c, float r, vec2 p) {\n vec2 d = p - c;\n float dist2 = dot(d, d);\n return (r * r) / dist2;\n}\n\nvoid main() {\n vec2 fc = gl_FragCoord.xy;\n float scale = iAnimationSize / iResolution.y;\n vec2 coord = (fc - iResolution.xy * 0.5) * scale;\n vec2 mouseW = (iMouse.xy - iResolution.xy * 0.5) * scale;\n float m1 = 0.0;\n for (int i = 0; i < 50; i++) {\n if (i >= iBallCount) break;\n m1 += getMetaBallValue(iMetaBalls[i].xy, iMetaBalls[i].z, coord);\n }\n float m2 = getMetaBallValue(mouseW, iCursorBallSize, coord);\n float total = m1 + m2;\n float f = smoothstep(-1.0, 1.0, (total - 1.3) / min(1.0, fwidth(total)));\n vec3 cFinal = vec3(0.0);\n if (total > 0.0) {\n float alpha1 = m1 / total;\n float alpha2 = m2 / total;\n cFinal = iColor * alpha1 + iCursorColor * alpha2;\n }\n outColor = vec4(cFinal * f, enableTransparency ? f : 1.0);\n}\n`;\n\nconst MetaBalls = ({\n className = '',\n color = '#ffffff',\n speed = 0.3,\n enableMouseInteraction = true,\n hoverSmoothness = 0.05,\n animationSize = 30,\n ballCount = 15,\n clumpFactor = 1,\n cursorBallSize = 3,\n cursorBallColor = '#ffffff',\n enableTransparency = false\n}) => {\n const containerRef = useRef(null);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const dpr = 1;\n const renderer = new Renderer({ dpr, alpha: true, premultipliedAlpha: false });\n const gl = renderer.gl;\n gl.clearColor(0, 0, 0, enableTransparency ? 0 : 1);\n container.appendChild(gl.canvas);\n\n const camera = new Camera(gl, {\n left: -1,\n right: 1,\n top: 1,\n bottom: -1,\n near: 0.1,\n far: 10\n });\n camera.position.z = 1;\n\n const geometry = new Triangle(gl);\n const [r1, g1, b1] = parseHexColor(color);\n const [r2, g2, b2] = parseHexColor(cursorBallColor);\n\n const metaBallsUniform = [];\n for (let i = 0; i < 50; i++) {\n metaBallsUniform.push(new Vec3(0, 0, 0));\n }\n\n const program = new Program(gl, {\n vertex,\n fragment,\n uniforms: {\n iTime: { value: 0 },\n iResolution: { value: new Vec3(0, 0, 0) },\n iMouse: { value: new Vec3(0, 0, 0) },\n iColor: { value: new Vec3(r1, g1, b1) },\n iCursorColor: { value: new Vec3(r2, g2, b2) },\n iAnimationSize: { value: animationSize },\n iBallCount: { value: ballCount },\n iCursorBallSize: { value: cursorBallSize },\n iMetaBalls: { value: metaBallsUniform },\n iClumpFactor: { value: clumpFactor },\n enableTransparency: { value: enableTransparency }\n }\n });\n\n const mesh = new Mesh(gl, { geometry, program });\n const scene = new Transform();\n mesh.setParent(scene);\n\n const maxBalls = 50;\n const effectiveBallCount = Math.min(ballCount, maxBalls);\n const ballParams = [];\n for (let i = 0; i < effectiveBallCount; i++) {\n const idx = i + 1;\n const h1 = hash31(idx);\n const st = h1[0] * (2 * Math.PI);\n const dtFactor = 0.1 * Math.PI + h1[1] * (0.4 * Math.PI - 0.1 * Math.PI);\n const baseScale = 5.0 + h1[1] * (10.0 - 5.0);\n const h2 = hash33(h1);\n const toggle = Math.floor(h2[0] * 2.0);\n const radiusVal = 0.5 + h2[2] * (2.0 - 0.5);\n ballParams.push({ st, dtFactor, baseScale, toggle, radius: radiusVal });\n }\n\n const mouseBallPos = { x: 0, y: 0 };\n let pointerInside = false;\n let pointerX = 0;\n let pointerY = 0;\n\n function resize() {\n if (!container) return;\n const width = container.clientWidth;\n const height = container.clientHeight;\n renderer.setSize(width * dpr, height * dpr);\n gl.canvas.style.width = width + 'px';\n gl.canvas.style.height = height + 'px';\n program.uniforms.iResolution.value.set(gl.canvas.width, gl.canvas.height, 0);\n }\n window.addEventListener('resize', resize);\n resize();\n\n function onPointerMove(e) {\n if (!enableMouseInteraction) return;\n const rect = container.getBoundingClientRect();\n const px = e.clientX - rect.left;\n const py = e.clientY - rect.top;\n pointerX = (px / rect.width) * gl.canvas.width;\n pointerY = (1 - py / rect.height) * gl.canvas.height;\n }\n function onPointerEnter() {\n if (!enableMouseInteraction) return;\n pointerInside = true;\n }\n function onPointerLeave() {\n if (!enableMouseInteraction) return;\n pointerInside = false;\n }\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerenter', onPointerEnter);\n container.addEventListener('pointerleave', onPointerLeave);\n\n const startTime = performance.now();\n let animationFrameId;\n function update(t) {\n animationFrameId = requestAnimationFrame(update);\n const elapsed = (t - startTime) * 0.001;\n program.uniforms.iTime.value = elapsed;\n\n for (let i = 0; i < effectiveBallCount; i++) {\n const p = ballParams[i];\n const dt = elapsed * speed * p.dtFactor;\n const th = p.st + dt;\n const x = Math.cos(th);\n const y = Math.sin(th + dt * p.toggle);\n const posX = x * p.baseScale * clumpFactor;\n const posY = y * p.baseScale * clumpFactor;\n metaBallsUniform[i].set(posX, posY, p.radius);\n }\n\n let targetX, targetY;\n if (pointerInside) {\n targetX = pointerX;\n targetY = pointerY;\n } else {\n const cx = gl.canvas.width * 0.5;\n const cy = gl.canvas.height * 0.5;\n const rx = gl.canvas.width * 0.15;\n const ry = gl.canvas.height * 0.15;\n targetX = cx + Math.cos(elapsed * speed) * rx;\n targetY = cy + Math.sin(elapsed * speed) * ry;\n }\n mouseBallPos.x += (targetX - mouseBallPos.x) * hoverSmoothness;\n mouseBallPos.y += (targetY - mouseBallPos.y) * hoverSmoothness;\n program.uniforms.iMouse.value.set(mouseBallPos.x, mouseBallPos.y, 0);\n\n renderer.render({ scene, camera });\n }\n animationFrameId = requestAnimationFrame(update);\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n window.removeEventListener('resize', resize);\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerenter', onPointerEnter);\n container.removeEventListener('pointerleave', onPointerLeave);\n container.removeChild(gl.canvas);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n };\n }, [\n color,\n cursorBallColor,\n speed,\n enableMouseInteraction,\n hoverSmoothness,\n animationSize,\n ballCount,\n clumpFactor,\n cursorBallSize,\n enableTransparency\n ]);\n\n return
;\n};\n\nexport default MetaBalls;\n" } ], "registryDependencies": [], diff --git a/public/r/SideRays-TS-TW.json b/public/r/SideRays-TS-TW.json index 17775972f..645e14559 100644 --- a/public/r/SideRays-TS-TW.json +++ b/public/r/SideRays-TS-TW.json @@ -8,7 +8,7 @@ { "type": "registry:component", "path": "SideRays/SideRays.tsx", - "content": "import { useRef, useEffect, useState } from 'react';\nimport { Renderer, Program, Triangle, Mesh } from 'ogl';\n\ntype Origin = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';\n\ninterface SideRaysProps {\n speed?: number;\n rayColor1?: string;\n rayColor2?: string;\n intensity?: number;\n spread?: number;\n origin?: Origin;\n tilt?: number;\n saturation?: number;\n blend?: number;\n falloff?: number;\n opacity?: number;\n className?: string;\n}\n\nconst hexToRgb = (hex: string): [number, number, number] => {\n const m = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return m ? [parseInt(m[1], 16) / 255, parseInt(m[2], 16) / 255, parseInt(m[3], 16) / 255] : [1, 1, 1];\n};\n\nconst originToFlip = (origin: Origin): [number, number] => {\n switch (origin) {\n case 'top-left': return [1, 0];\n case 'bottom-right': return [0, 1];\n case 'bottom-left': return [1, 1];\n default: return [0, 0];\n }\n};\n\nconst SideRays = ({\n speed = 2.5,\n rayColor1 = '#EAB308',\n rayColor2 = '#96c8ff',\n intensity = 2,\n spread = 2,\n origin = 'top-right',\n tilt = 0,\n saturation = 1.5,\n blend = 0.75,\n falloff = 2.0,\n opacity = 1.0,\n className = ''\n}: SideRaysProps) => {\n const containerRef = useRef(null);\n const uniformsRef = useRef | null>(null);\n const rendererRef = useRef(null);\n const animationIdRef = useRef(null);\n const meshRef = useRef(null);\n const cleanupFunctionRef = useRef<(() => void) | null>(null);\n const [isVisible, setIsVisible] = useState(false);\n const observerRef = useRef(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n observerRef.current = new IntersectionObserver(\n entries => {\n const entry = entries[0];\n setIsVisible(entry.isIntersecting);\n },\n { threshold: 0.1 }\n );\n\n observerRef.current.observe(containerRef.current);\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, []);\n\n useEffect(() => {\n if (!isVisible || !containerRef.current) return;\n\n if (cleanupFunctionRef.current) {\n cleanupFunctionRef.current();\n cleanupFunctionRef.current = null;\n }\n\n const initializeWebGL = async () => {\n if (!containerRef.current) return;\n\n await new Promise(resolve => setTimeout(resolve, 10));\n\n if (!containerRef.current) return;\n\n const renderer = new Renderer({\n dpr: Math.min(window.devicePixelRatio, 2),\n alpha: true\n });\n rendererRef.current = renderer;\n\n const gl = renderer.gl;\n gl.canvas.style.width = '100%';\n gl.canvas.style.height = '100%';\n\n while (containerRef.current.firstChild) {\n containerRef.current.removeChild(containerRef.current.firstChild);\n }\n containerRef.current.appendChild(gl.canvas);\n\n const vert = `\nattribute vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}`;\n\n const frag = `precision highp float;\n\nuniform float iTime;\nuniform vec2 iResolution;\nuniform float iSpeed;\nuniform vec3 iRayColor1;\nuniform vec3 iRayColor2;\nuniform float iIntensity;\nuniform float iSpread;\nuniform float iFlipX;\nuniform float iFlipY;\nuniform float iTilt;\nuniform float iSaturation;\nuniform float iBlend;\nuniform float iFalloff;\nuniform float iOpacity;\n\nfloat rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord, float seedA, float seedB, float speed) {\n vec2 sourceToCoord = coord - raySource;\n float cosAngle = dot(normalize(sourceToCoord), rayRefDirection);\n return clamp(\n (0.45 + 0.15 * sin(cosAngle * seedA + iTime * speed)) +\n (0.3 + 0.2 * cos(-cosAngle * seedB + iTime * speed)),\n 0.0, 1.0) *\n clamp((iResolution.x - length(sourceToCoord)) / iResolution.x, 0.5, 1.0);\n}\n\nvoid main() {\n vec2 fragCoord = gl_FragCoord.xy;\n if (iFlipX > 0.5) fragCoord.x = iResolution.x - fragCoord.x;\n if (iFlipY > 0.5) fragCoord.y = iResolution.y - fragCoord.y;\n\n vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y);\n vec2 rayPos = vec2(iResolution.x * 1.1, -0.5 * iResolution.y);\n\n float tiltRad = iTilt * 3.14159265 / 180.0;\n float cs = cos(tiltRad);\n float sn = sin(tiltRad);\n vec2 rel = coord - rayPos;\n vec2 tiltedCoord = vec2(rel.x * cs - rel.y * sn, rel.x * sn + rel.y * cs) + rayPos;\n\n float halfSpread = iSpread * 0.275;\n vec2 rayRefDir1 = normalize(vec2(cos(0.785398 + halfSpread), sin(0.785398 + halfSpread)));\n vec2 rayRefDir2 = normalize(vec2(cos(0.785398 - halfSpread), sin(0.785398 - halfSpread)));\n\n vec4 rays1 = vec4(iRayColor1, 1.0) * rayStrength(rayPos, rayRefDir1, tiltedCoord, 36.2214, 21.11349, iSpeed);\n vec4 rays2 = vec4(iRayColor2, 1.0) * rayStrength(rayPos, rayRefDir2, tiltedCoord, 22.3991, 18.0234, iSpeed * 0.2);\n\n vec4 color = rays1 * (1.0 - iBlend) * 0.9 + rays2 * iBlend * 0.9;\n\n float distanceToLight = length(fragCoord.xy - vec2(rayPos.x, iResolution.y - rayPos.y)) / iResolution.y;\n float brightness = iIntensity * 0.4 / pow(max(distanceToLight, 0.001), iFalloff);\n color.rgb *= brightness;\n\n float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));\n color.rgb = mix(vec3(gray), color.rgb, iSaturation);\n\n color.a = max(color.r, max(color.g, color.b)) * iOpacity;\n gl_FragColor = color;\n}`;\n\n const [flipX, flipY] = originToFlip(origin);\n const uniforms = {\n iTime: { value: 0 },\n iResolution: { value: [1, 1] as number[] },\n iSpeed: { value: speed },\n iRayColor1: { value: hexToRgb(rayColor1) as number[] },\n iRayColor2: { value: hexToRgb(rayColor2) as number[] },\n iIntensity: { value: intensity },\n iSpread: { value: spread },\n iFlipX: { value: flipX },\n iFlipY: { value: flipY },\n iTilt: { value: tilt },\n iSaturation: { value: saturation },\n iBlend: { value: blend },\n iFalloff: { value: falloff },\n iOpacity: { value: opacity }\n };\n uniformsRef.current = uniforms;\n\n const geometry = new Triangle(gl);\n const program = new Program(gl, { vertex: vert, fragment: frag, uniforms });\n const mesh = new Mesh(gl, { geometry, program });\n meshRef.current = mesh;\n\n const updateSize = () => {\n if (!containerRef.current || !renderer) return;\n renderer.dpr = Math.min(window.devicePixelRatio, 2);\n const { clientWidth: w, clientHeight: h } = containerRef.current;\n renderer.setSize(w, h);\n uniforms.iResolution.value = [w * renderer.dpr, h * renderer.dpr];\n };\n\n const loop = (t: number) => {\n if (!rendererRef.current || !uniformsRef.current || !meshRef.current) return;\n uniforms.iTime.value = t * 0.001;\n try {\n renderer.render({ scene: mesh });\n animationIdRef.current = requestAnimationFrame(loop);\n } catch (e) {\n return;\n }\n };\n\n window.addEventListener('resize', updateSize);\n updateSize();\n animationIdRef.current = requestAnimationFrame(loop);\n\n cleanupFunctionRef.current = () => {\n if (animationIdRef.current) {\n cancelAnimationFrame(animationIdRef.current);\n animationIdRef.current = null;\n }\n window.removeEventListener('resize', updateSize);\n if (renderer) {\n try {\n const loseCtx = renderer.gl.getExtension('WEBGL_lose_context');\n if (loseCtx) loseCtx.loseContext();\n const canvas = renderer.gl.canvas;\n if (canvas && canvas.parentNode) canvas.parentNode.removeChild(canvas);\n } catch (e) {}\n }\n rendererRef.current = null;\n uniformsRef.current = null;\n meshRef.current = null;\n };\n };\n\n initializeWebGL();\n\n return () => {\n if (cleanupFunctionRef.current) {\n cleanupFunctionRef.current();\n cleanupFunctionRef.current = null;\n }\n };\n }, [isVisible, speed, rayColor1, rayColor2, intensity, spread, origin, tilt, saturation, blend, falloff, opacity]);\n\n useEffect(() => {\n if (!uniformsRef.current) return;\n const u = uniformsRef.current;\n u.iSpeed.value = speed;\n u.iRayColor1.value = hexToRgb(rayColor1);\n u.iRayColor2.value = hexToRgb(rayColor2);\n u.iIntensity.value = intensity;\n u.iSpread.value = spread;\n const [flipX, flipY] = originToFlip(origin);\n u.iFlipX.value = flipX;\n u.iFlipY.value = flipY;\n u.iTilt.value = tilt;\n u.iSaturation.value = saturation;\n u.iBlend.value = blend;\n u.iFalloff.value = falloff;\n u.iOpacity.value = opacity;\n }, [speed, rayColor1, rayColor2, intensity, spread, origin, tilt, saturation, blend, falloff, opacity]);\n\n return (\n \n );\n};\n\nexport default SideRays;\n" + "content": "import { useRef, useEffect, useState } from 'react';\nimport { Renderer, Program, Triangle, Mesh } from 'ogl';\n\ntype Origin = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';\n\ninterface SideRaysProps {\n speed?: number;\n rayColor1?: string;\n rayColor2?: string;\n intensity?: number;\n spread?: number;\n origin?: Origin;\n tilt?: number;\n saturation?: number;\n blend?: number;\n falloff?: number;\n opacity?: number;\n className?: string;\n}\n\nconst hexToRgb = (hex: string): [number, number, number] => {\n const m = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return m ? [parseInt(m[1], 16) / 255, parseInt(m[2], 16) / 255, parseInt(m[3], 16) / 255] : [1, 1, 1];\n};\n\nconst originToFlip = (origin: Origin): [number, number] => {\n switch (origin) {\n case 'top-left': return [1, 0];\n case 'bottom-right': return [0, 1];\n case 'bottom-left': return [1, 1];\n default: return [0, 0];\n }\n};\n\nconst SideRays = ({\n speed = 2.5,\n rayColor1 = '#EAB308',\n rayColor2 = '#96c8ff',\n intensity = 2,\n spread = 2,\n origin = 'top-right',\n tilt = 0,\n saturation = 1.5,\n blend = 0.75,\n falloff = 1.6,\n opacity = 1.0,\n className = ''\n}: SideRaysProps) => {\n const containerRef = useRef(null);\n const uniformsRef = useRef | null>(null);\n const rendererRef = useRef(null);\n const animationIdRef = useRef(null);\n const meshRef = useRef(null);\n const cleanupFunctionRef = useRef<(() => void) | null>(null);\n const [isVisible, setIsVisible] = useState(false);\n const observerRef = useRef(null);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n observerRef.current = new IntersectionObserver(\n entries => {\n const entry = entries[0];\n setIsVisible(entry.isIntersecting);\n },\n { threshold: 0.1 }\n );\n\n observerRef.current.observe(containerRef.current);\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, []);\n\n useEffect(() => {\n if (!isVisible || !containerRef.current) return;\n\n if (cleanupFunctionRef.current) {\n cleanupFunctionRef.current();\n cleanupFunctionRef.current = null;\n }\n\n const initializeWebGL = async () => {\n if (!containerRef.current) return;\n\n await new Promise(resolve => setTimeout(resolve, 10));\n\n if (!containerRef.current) return;\n\n const renderer = new Renderer({\n dpr: Math.min(window.devicePixelRatio, 2),\n alpha: true\n });\n rendererRef.current = renderer;\n\n const gl = renderer.gl;\n gl.canvas.style.width = '100%';\n gl.canvas.style.height = '100%';\n\n while (containerRef.current.firstChild) {\n containerRef.current.removeChild(containerRef.current.firstChild);\n }\n containerRef.current.appendChild(gl.canvas);\n\n const vert = `\nattribute vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}`;\n\n const frag = `precision highp float;\n\nuniform float iTime;\nuniform vec2 iResolution;\nuniform float iSpeed;\nuniform vec3 iRayColor1;\nuniform vec3 iRayColor2;\nuniform float iIntensity;\nuniform float iSpread;\nuniform float iFlipX;\nuniform float iFlipY;\nuniform float iTilt;\nuniform float iSaturation;\nuniform float iBlend;\nuniform float iFalloff;\nuniform float iOpacity;\n\nfloat rayStrength(vec2 raySource, vec2 rayRefDirection, vec2 coord, float seedA, float seedB, float speed) {\n vec2 sourceToCoord = coord - raySource;\n float cosAngle = dot(normalize(sourceToCoord), rayRefDirection);\n return clamp(\n (0.45 + 0.15 * sin(cosAngle * seedA + iTime * speed)) +\n (0.3 + 0.2 * cos(-cosAngle * seedB + iTime * speed)),\n 0.0, 1.0) *\n clamp((iResolution.x - length(sourceToCoord)) / iResolution.x, 0.5, 1.0);\n}\n\nvoid main() {\n vec2 fragCoord = gl_FragCoord.xy;\n if (iFlipX > 0.5) fragCoord.x = iResolution.x - fragCoord.x;\n if (iFlipY > 0.5) fragCoord.y = iResolution.y - fragCoord.y;\n\n vec2 coord = vec2(fragCoord.x, iResolution.y - fragCoord.y);\n vec2 rayPos = vec2(iResolution.x * 1.1, -0.5 * iResolution.y);\n\n float tiltRad = iTilt * 3.14159265 / 180.0;\n float cs = cos(tiltRad);\n float sn = sin(tiltRad);\n vec2 rel = coord - rayPos;\n vec2 tiltedCoord = vec2(rel.x * cs - rel.y * sn, rel.x * sn + rel.y * cs) + rayPos;\n\n float halfSpread = iSpread * 0.275;\n vec2 rayRefDir1 = normalize(vec2(cos(0.785398 + halfSpread), sin(0.785398 + halfSpread)));\n vec2 rayRefDir2 = normalize(vec2(cos(0.785398 - halfSpread), sin(0.785398 - halfSpread)));\n\n vec4 rays1 = vec4(iRayColor1, 1.0) * rayStrength(rayPos, rayRefDir1, tiltedCoord, 36.2214, 21.11349, iSpeed);\n vec4 rays2 = vec4(iRayColor2, 1.0) * rayStrength(rayPos, rayRefDir2, tiltedCoord, 22.3991, 18.0234, iSpeed * 0.2);\n\n vec4 color = rays1 * (1.0 - iBlend) * 0.9 + rays2 * iBlend * 0.9;\n\n float distanceToLight = length(fragCoord.xy - vec2(rayPos.x, iResolution.y - rayPos.y)) / iResolution.y;\n float brightness = iIntensity * 0.4 / pow(max(distanceToLight, 0.001), iFalloff);\n color.rgb *= brightness;\n\n float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));\n color.rgb = mix(vec3(gray), color.rgb, iSaturation);\n\n color.a = max(color.r, max(color.g, color.b)) * iOpacity;\n gl_FragColor = color;\n}`;\n\n const [flipX, flipY] = originToFlip(origin);\n const uniforms = {\n iTime: { value: 0 },\n iResolution: { value: [1, 1] as number[] },\n iSpeed: { value: speed },\n iRayColor1: { value: hexToRgb(rayColor1) as number[] },\n iRayColor2: { value: hexToRgb(rayColor2) as number[] },\n iIntensity: { value: intensity },\n iSpread: { value: spread },\n iFlipX: { value: flipX },\n iFlipY: { value: flipY },\n iTilt: { value: tilt },\n iSaturation: { value: saturation },\n iBlend: { value: blend },\n iFalloff: { value: falloff },\n iOpacity: { value: opacity }\n };\n uniformsRef.current = uniforms;\n\n const geometry = new Triangle(gl);\n const program = new Program(gl, { vertex: vert, fragment: frag, uniforms });\n const mesh = new Mesh(gl, { geometry, program });\n meshRef.current = mesh;\n\n const updateSize = () => {\n if (!containerRef.current || !renderer) return;\n renderer.dpr = Math.min(window.devicePixelRatio, 2);\n const { clientWidth: w, clientHeight: h } = containerRef.current;\n renderer.setSize(w, h);\n uniforms.iResolution.value = [w * renderer.dpr, h * renderer.dpr];\n };\n\n const loop = (t: number) => {\n if (!rendererRef.current || !uniformsRef.current || !meshRef.current) return;\n uniforms.iTime.value = t * 0.001;\n try {\n renderer.render({ scene: mesh });\n animationIdRef.current = requestAnimationFrame(loop);\n } catch (e) {\n return;\n }\n };\n\n window.addEventListener('resize', updateSize);\n updateSize();\n animationIdRef.current = requestAnimationFrame(loop);\n\n cleanupFunctionRef.current = () => {\n if (animationIdRef.current) {\n cancelAnimationFrame(animationIdRef.current);\n animationIdRef.current = null;\n }\n window.removeEventListener('resize', updateSize);\n if (renderer) {\n try {\n const loseCtx = renderer.gl.getExtension('WEBGL_lose_context');\n if (loseCtx) loseCtx.loseContext();\n const canvas = renderer.gl.canvas;\n if (canvas && canvas.parentNode) canvas.parentNode.removeChild(canvas);\n } catch (e) {}\n }\n rendererRef.current = null;\n uniformsRef.current = null;\n meshRef.current = null;\n };\n };\n\n initializeWebGL();\n\n return () => {\n if (cleanupFunctionRef.current) {\n cleanupFunctionRef.current();\n cleanupFunctionRef.current = null;\n }\n };\n }, [isVisible, speed, rayColor1, rayColor2, intensity, spread, origin, tilt, saturation, blend, falloff, opacity]);\n\n useEffect(() => {\n if (!uniformsRef.current) return;\n const u = uniformsRef.current;\n u.iSpeed.value = speed;\n u.iRayColor1.value = hexToRgb(rayColor1);\n u.iRayColor2.value = hexToRgb(rayColor2);\n u.iIntensity.value = intensity;\n u.iSpread.value = spread;\n const [flipX, flipY] = originToFlip(origin);\n u.iFlipX.value = flipX;\n u.iFlipY.value = flipY;\n u.iTilt.value = tilt;\n u.iSaturation.value = saturation;\n u.iBlend.value = blend;\n u.iFalloff.value = falloff;\n u.iOpacity.value = opacity;\n }, [speed, rayColor1, rayColor2, intensity, spread, origin, tilt, saturation, blend, falloff, opacity]);\n\n return (\n \n );\n};\n\nexport default SideRays;\n" } ], "registryDependencies": [], diff --git a/src/content/Animations/MetaBalls/MetaBalls.jsx b/src/content/Animations/MetaBalls/MetaBalls.jsx index 894ce781f..7f37dabae 100644 --- a/src/content/Animations/MetaBalls/MetaBalls.jsx +++ b/src/content/Animations/MetaBalls/MetaBalls.jsx @@ -106,7 +106,7 @@ const MetaBalls = ({ clumpFactor = 1, cursorBallSize = 3, cursorBallColor = '#ffffff', - enableTransparency = true + enableTransparency = false }) => { const containerRef = useRef(null); diff --git a/src/content/TextAnimations/GlitchText/GlitchText.jsx b/src/content/TextAnimations/GlitchText/GlitchText.jsx index dbd2c0740..2ad92d985 100644 --- a/src/content/TextAnimations/GlitchText/GlitchText.jsx +++ b/src/content/TextAnimations/GlitchText/GlitchText.jsx @@ -1,6 +1,6 @@ import './GlitchText.css'; -const GlitchText = ({ children, speed = 1, enableShadows = true, enableOnHover = true, className = '' }) => { +const GlitchText = ({ children, speed = 0.5, enableShadows = true, enableOnHover = false, className = '' }) => { const inlineStyles = { '--after-duration': `${speed * 3}s`, '--before-duration': `${speed * 2}s`, diff --git a/src/demo/Animations/MetaBallsDemo.jsx b/src/demo/Animations/MetaBallsDemo.jsx index 03c21c75d..e35299855 100644 --- a/src/demo/Animations/MetaBallsDemo.jsx +++ b/src/demo/Animations/MetaBallsDemo.jsx @@ -129,6 +129,7 @@ const MetaBallsDemo = () => { hoverSmoothness={hoverSmoothness} clumpFactor={clumpFactor} speed={speed} + enableTransparency /> diff --git a/src/ts-tailwind/Backgrounds/SideRays/SideRays.tsx b/src/ts-tailwind/Backgrounds/SideRays/SideRays.tsx index 2e3915cfe..ed8e4c1c9 100644 --- a/src/ts-tailwind/Backgrounds/SideRays/SideRays.tsx +++ b/src/ts-tailwind/Backgrounds/SideRays/SideRays.tsx @@ -42,7 +42,7 @@ const SideRays = ({ tilt = 0, saturation = 1.5, blend = 0.75, - falloff = 2.0, + falloff = 1.6, opacity = 1.0, className = '' }: SideRaysProps) => {