Files
vue-bits/public/r/Grainient.json
2026-02-04 10:21:07 +05:30

1 line
8.6 KiB
JSON

{"name":"Grainient","title":"Grainient","description":"Grainy gradient swirls with soft wave distortion.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport { Mesh, Program, Renderer, Triangle } from 'ogl';\nimport { onBeforeUnmount, onMounted, useTemplateRef, watch } from 'vue';\n\ninterface GrainientProps {\n timeSpeed?: number;\n colorBalance?: number;\n warpStrength?: number;\n warpFrequency?: number;\n warpSpeed?: number;\n warpAmplitude?: number;\n blendAngle?: number;\n blendSoftness?: number;\n rotationAmount?: number;\n noiseScale?: number;\n grainAmount?: number;\n grainScale?: number;\n grainAnimated?: boolean;\n contrast?: number;\n gamma?: number;\n saturation?: number;\n centerX?: number;\n centerY?: number;\n zoom?: number;\n color1?: string;\n color2?: string;\n color3?: string;\n className?: string;\n}\n\nconst hexToRgb = (hex: string): [number, number, number] => {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return [1, 1, 1];\n return [parseInt(result[1], 16) / 255, parseInt(result[2], 16) / 255, parseInt(result[3], 16) / 255];\n};\n\nconst vertex = `#version 300 es\nin 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 vec2 iResolution;\nuniform float iTime;\nuniform float uTimeSpeed;\nuniform float uColorBalance;\nuniform float uWarpStrength;\nuniform float uWarpFrequency;\nuniform float uWarpSpeed;\nuniform float uWarpAmplitude;\nuniform float uBlendAngle;\nuniform float uBlendSoftness;\nuniform float uRotationAmount;\nuniform float uNoiseScale;\nuniform float uGrainAmount;\nuniform float uGrainScale;\nuniform float uGrainAnimated;\nuniform float uContrast;\nuniform float uGamma;\nuniform float uSaturation;\nuniform vec2 uCenterOffset;\nuniform float uZoom;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform vec3 uColor3;\nout vec4 fragColor;\n#define S(a,b,t) smoothstep(a,b,t)\nmat2 Rot(float a){float s=sin(a),c=cos(a);return mat2(c,-s,s,c);} \nvec2 hash(vec2 p){p=vec2(dot(p,vec2(2127.1,81.17)),dot(p,vec2(1269.5,283.37)));return fract(sin(p)*43758.5453);} \nfloat noise(vec2 p){vec2 i=floor(p),f=fract(p),u=f*f*(3.0-2.0*f);float n=mix(mix(dot(-1.0+2.0*hash(i+vec2(0.0,0.0)),f-vec2(0.0,0.0)),dot(-1.0+2.0*hash(i+vec2(1.0,0.0)),f-vec2(1.0,0.0)),u.x),mix(dot(-1.0+2.0*hash(i+vec2(0.0,1.0)),f-vec2(0.0,1.0)),dot(-1.0+2.0*hash(i+vec2(1.0,1.0)),f-vec2(1.0,1.0)),u.x),u.y);return 0.5+0.5*n;}\nvoid mainImage(out vec4 o, vec2 C){\n float t=iTime*uTimeSpeed;\n vec2 uv=C/iResolution.xy;\n float ratio=iResolution.x/iResolution.y;\n vec2 tuv=uv-0.5+uCenterOffset;\n tuv/=max(uZoom,0.001);\n\n float degree=noise(vec2(t*0.1,tuv.x*tuv.y)*uNoiseScale);\n tuv.y*=1.0/ratio;\n tuv*=Rot(radians((degree-0.5)*uRotationAmount+180.0));\n tuv.y*=ratio;\n\n float frequency=uWarpFrequency;\n float ws=max(uWarpStrength,0.001);\n float amplitude=uWarpAmplitude/ws;\n float warpTime=t*uWarpSpeed;\n tuv.x+=sin(tuv.y*frequency+warpTime)/amplitude;\n tuv.y+=sin(tuv.x*(frequency*1.5)+warpTime)/(amplitude*0.5);\n\n vec3 colLav=uColor1;\n vec3 colOrg=uColor2;\n vec3 colDark=uColor3;\n float b=uColorBalance;\n float s=max(uBlendSoftness,0.0);\n mat2 blendRot=Rot(radians(uBlendAngle));\n float blendX=(tuv*blendRot).x;\n float edge0=-0.3-b-s;\n float edge1=0.2-b+s;\n float v0=0.5-b+s;\n float v1=-0.3-b-s;\n vec3 layer1=mix(colDark,colOrg,S(edge0,edge1,blendX));\n vec3 layer2=mix(colOrg,colLav,S(edge0,edge1,blendX));\n vec3 col=mix(layer1,layer2,S(v0,v1,tuv.y));\n\n vec2 grainUv=uv*max(uGrainScale,0.001);\n if(uGrainAnimated>0.5){grainUv+=vec2(iTime*0.05);} \n float grain=fract(sin(dot(grainUv,vec2(12.9898,78.233)))*43758.5453);\n col+=(grain-0.5)*uGrainAmount;\n\n col=(col-0.5)*uContrast+0.5;\n float luma=dot(col,vec3(0.2126,0.7152,0.0722));\n col=mix(vec3(luma),col,uSaturation);\n col=pow(max(col,0.0),vec3(1.0/max(uGamma,0.001)));\n col=clamp(col,0.0,1.0);\n\n o=vec4(col,1.0);\n}\nvoid main(){\n vec4 o=vec4(0.0);\n mainImage(o,gl_FragCoord.xy);\n fragColor=o;\n}\n`;\n\nconst props = withDefaults(defineProps<GrainientProps>(), {\n timeSpeed: 0.25,\n colorBalance: 0.0,\n warpStrength: 1.0,\n warpFrequency: 5.0,\n warpSpeed: 2.0,\n warpAmplitude: 50.0,\n blendAngle: 0.0,\n blendSoftness: 0.05,\n rotationAmount: 500.0,\n noiseScale: 2.0,\n grainAmount: 0.1,\n grainScale: 2.0,\n grainAnimated: false,\n contrast: 1.5,\n gamma: 1.0,\n saturation: 1.0,\n centerX: 0.0,\n centerY: 0.0,\n zoom: 0.9,\n color1: '#FF9FFC',\n color2: '#5227FF',\n color3: '#B19EEF',\n className: ''\n});\n\nconst containerRef = useTemplateRef<HTMLDivElement>('containerRef');\n\nlet cleanup: (() => void) | null = null;\nconst setup = () => {\n if (!containerRef.value) return;\n\n const renderer = new Renderer({\n webgl: 2,\n alpha: true,\n antialias: false,\n dpr: Math.min(window.devicePixelRatio || 1, 2)\n });\n\n const gl = renderer.gl;\n const canvas = gl.canvas as HTMLCanvasElement;\n canvas.style.width = '100%';\n canvas.style.height = '100%';\n canvas.style.display = 'block';\n\n const container = containerRef.value;\n container.appendChild(canvas);\n\n const geometry = new Triangle(gl);\n const program = new Program(gl, {\n vertex,\n fragment,\n uniforms: {\n iTime: { value: 0 },\n iResolution: { value: new Float32Array([1, 1]) },\n uTimeSpeed: { value: props.timeSpeed },\n uColorBalance: { value: props.colorBalance },\n uWarpStrength: { value: props.warpStrength },\n uWarpFrequency: { value: props.warpFrequency },\n uWarpSpeed: { value: props.warpSpeed },\n uWarpAmplitude: { value: props.warpAmplitude },\n uBlendAngle: { value: props.blendAngle },\n uBlendSoftness: { value: props.blendSoftness },\n uRotationAmount: { value: props.rotationAmount },\n uNoiseScale: { value: props.noiseScale },\n uGrainAmount: { value: props.grainAmount },\n uGrainScale: { value: props.grainScale },\n uGrainAnimated: { value: props.grainAnimated ? 1.0 : 0.0 },\n uContrast: { value: props.contrast },\n uGamma: { value: props.gamma },\n uSaturation: { value: props.saturation },\n uCenterOffset: { value: new Float32Array([props.centerX, props.centerY]) },\n uZoom: { value: props.zoom },\n uColor1: { value: new Float32Array(hexToRgb(props.color1)) },\n uColor2: { value: new Float32Array(hexToRgb(props.color2)) },\n uColor3: { value: new Float32Array(hexToRgb(props.color3)) }\n }\n });\n\n const mesh = new Mesh(gl, { geometry, program });\n\n const setSize = () => {\n const rect = container.getBoundingClientRect();\n const width = Math.max(1, Math.floor(rect.width));\n const height = Math.max(1, Math.floor(rect.height));\n renderer.setSize(width, height);\n const res = (program.uniforms.iResolution as { value: Float32Array }).value;\n res[0] = gl.drawingBufferWidth;\n res[1] = gl.drawingBufferHeight;\n };\n\n const ro = new ResizeObserver(setSize);\n ro.observe(container);\n setSize();\n\n let raf = 0;\n const t0 = performance.now();\n const loop = (t: number) => {\n (program.uniforms.iTime as { value: number }).value = (t - t0) * 0.001;\n renderer.render({ scene: mesh });\n raf = requestAnimationFrame(loop);\n };\n raf = requestAnimationFrame(loop);\n\n cleanup = () => {\n cancelAnimationFrame(raf);\n ro.disconnect();\n try {\n container.removeChild(canvas);\n } catch {\n // Ignore\n }\n };\n};\n\nonMounted(setup);\nonBeforeUnmount(() => {\n cleanup?.();\n});\n\nwatch(\n () => [\n props.timeSpeed,\n props.colorBalance,\n props.warpStrength,\n props.warpFrequency,\n props.warpSpeed,\n props.warpAmplitude,\n props.blendAngle,\n props.blendSoftness,\n props.rotationAmount,\n props.noiseScale,\n props.grainAmount,\n props.grainScale,\n props.grainAnimated,\n props.contrast,\n props.gamma,\n props.saturation,\n props.centerX,\n props.centerY,\n props.zoom,\n props.color1,\n props.color2,\n props.color3\n ],\n () => {\n cleanup?.();\n setup();\n },\n {\n deep: true\n }\n);\n</script>\n\n<template>\n <div ref=\"containerRef\" :class=\"['relative h-full w-full overflow-hidden', className]\" />\n</template>\n","path":"Grainient/Grainient.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"ogl","version":"^1.0.11"}],"devDependencies":[],"categories":["Backgrounds"]}