UNPKG

@firecms/neat

Version:

Beautiful 3D gradients for your website

398 lines (318 loc) 19.4 kB
(function(u,d){typeof exports=="object"&&typeof module<"u"?d(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],d):(u=typeof globalThis<"u"?globalThis:u||self,d(u.FireCMS={},u.THREE))})(this,function(u,d){"use strict";function T(t){if(t&&t.__esModule)return t;const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const o in t)if(o!=="default"){const i=Object.getOwnPropertyDescriptor(t,o);Object.defineProperty(e,o,i.get?i:{enumerable:!0,get:()=>t[o]})}}return e.default=t,Object.freeze(e)}const n=T(d),_=50,g=80,D=!0,b=5,k=new n.Clock,F=V();class B{_ref;_speed=-1;_horizontalPressure=-1;_verticalPressure=-1;_waveFrequencyX=-1;_waveFrequencyY=-1;_waveAmplitude=-1;_shadows=-1;_highlights=-1;_saturation=-1;_brightness=-1;_grainScale=-1;_grainIntensity=-1;_grainSparsity=-1;_grainSpeed=-1;_colorBlending=-1;_colors=[];_wireframe=!1;_backgroundColor="#FFFFFF";_backgroundAlpha=1;requestRef=-1;sizeObserver;sceneState;_yOffset=0;constructor(e){const{ref:o,speed:i=4,horizontalPressure:s=3,verticalPressure:a=3,waveFrequencyX:c=5,waveFrequencyY:f=5,waveAmplitude:h=3,colors:l,highlights:v=4,shadows:y=4,colorSaturation:z=0,colorBrightness:P=1,colorBlending:S=5,grainScale:Y=2,grainIntensity:W=.55,grainSparsity:X=0,grainSpeed:J=.1,wireframe:Q=!1,backgroundColor:Z="#FFFFFF",backgroundAlpha:$=1,resolution:ee=1,seed:E,yOffset:te=0}=e;this._ref=o,this.destroy=this.destroy.bind(this),this._initScene=this._initScene.bind(this),this._buildMaterial=this._buildMaterial.bind(this),this.speed=i,this.horizontalPressure=s,this.verticalPressure=a,this.waveFrequencyX=c,this.waveFrequencyY=f,this.waveAmplitude=h,this.colorBlending=S,this.grainScale=Y,this.grainIntensity=W,this.grainSparsity=X,this.grainSpeed=J,this.colors=l,this.shadows=y,this.highlights=v,this.colorSaturation=z,this.colorBrightness=P,this.wireframe=Q,this.backgroundColor=Z,this.backgroundAlpha=$,this.yOffset=te,this.sceneState=this._initScene(ee);let C=E!==void 0?E:U();const R=()=>{const{renderer:m,camera:x,scene:p,meshes:w}=this.sceneState;Math.floor(C*10)%5===0&&G(o),m.setClearColor(this._backgroundColor,this._backgroundAlpha),w.forEach(r=>{const re=this._ref.width,ie=this._ref.height,ne=[...this._colors.map(q=>{let j=new n.Color;return j.setStyle(q.color,""),{is_active:q.enabled,color:j,influence:q.influence}}),...Array.from({length:b-this._colors.length}).map(()=>({is_active:!1,color:new n.Color(0)}))];C+=k.getDelta()*this._speed,r.material.uniforms.u_time.value=C,r.material.uniforms.u_resolution={value:new n.Vector2(re,ie)},r.material.uniforms.u_color_pressure={value:new n.Vector2(this._horizontalPressure,this._verticalPressure)},r.material.uniforms.u_wave_frequency_x={value:this._waveFrequencyX},r.material.uniforms.u_wave_frequency_y={value:this._waveFrequencyY},r.material.uniforms.u_wave_amplitude={value:this._waveAmplitude},r.material.uniforms.u_plane_width={value:_},r.material.uniforms.u_plane_height={value:g},r.material.uniforms.u_color_blending={value:this._colorBlending},r.material.uniforms.u_colors={value:ne},r.material.uniforms.u_colors_count={value:b},r.material.uniforms.u_shadows={value:this._shadows},r.material.uniforms.u_highlights={value:this._highlights},r.material.uniforms.u_saturation={value:this._saturation},r.material.uniforms.u_brightness={value:this._brightness},r.material.uniforms.u_grain_intensity={value:this._grainIntensity},r.material.uniforms.u_grain_sparsity={value:this._grainSparsity},r.material.uniforms.u_grain_speed={value:this._grainSpeed},r.material.uniforms.u_grain_scale={value:this._grainScale},r.material.uniforms.u_y_offset={value:this._yOffset},r.material.wireframe=this._wireframe}),m.render(p,x),this.requestRef=requestAnimationFrame(R)},oe=()=>{const{renderer:m}=this.sceneState,x=m.domElement,p=x.clientWidth,w=x.clientHeight;this.sceneState.renderer.setSize(p,w,!1),A(this.sceneState.camera,p,w)};this.sizeObserver=new ResizeObserver(m=>{oe()}),this.sizeObserver.observe(o),R()}destroy(){this&&(cancelAnimationFrame(this.requestRef),this.sizeObserver.disconnect())}downloadAsPNG(e="neat.png"){console.log("Downloading as PNG",this._ref);const o=this._ref.toDataURL("image/png");console.log("data",o),H(o,e)}set speed(e){this._speed=e/20}set horizontalPressure(e){this._horizontalPressure=e/4}set verticalPressure(e){this._verticalPressure=e/4}set waveFrequencyX(e){this._waveFrequencyX=e*.04}set waveFrequencyY(e){this._waveFrequencyY=e*.04}set waveAmplitude(e){this._waveAmplitude=e*.75}set colors(e){this._colors=e}set highlights(e){this._highlights=e/100}set shadows(e){this._shadows=e/100}set colorSaturation(e){this._saturation=e/10}set colorBrightness(e){this._brightness=e}set colorBlending(e){this._colorBlending=e/10}set grainScale(e){this._grainScale=e==0?1:e}set grainIntensity(e){this._grainIntensity=e}set grainSparsity(e){this._grainSparsity=e}set grainSpeed(e){this._grainSpeed=e}set wireframe(e){this._wireframe=e}set resolution(e){this.sceneState=this._initScene(e)}set backgroundColor(e){this._backgroundColor=e}set backgroundAlpha(e){this._backgroundAlpha=e}set yOffset(e){this._yOffset=e}_initScene(e){const o=this._ref.width,i=this._ref.height,s=new n.WebGLRenderer({alpha:!0,preserveDrawingBuffer:!0,canvas:this._ref});s.setClearColor(16711680,.5),s.setSize(o,i,!1);const a=[],c=new n.Scene,f=this._buildMaterial(o,i),h=new n.PlaneGeometry(_,g,240*e,240*e),l=new n.Mesh(h,f);l.rotation.x=-Math.PI/3.5,l.position.z=-1,a.push(l),c.add(l);const v=new n.OrthographicCamera(0,0,0,0,0,0);return v.position.z=5,A(v,o,i),{renderer:s,camera:v,scene:c,meshes:a,resolution:e}}_buildMaterial(e,o){const i=[...this._colors.map(c=>({is_active:c.enabled,color:new n.Color(c.color),influence:c.influence})),...Array.from({length:b-this._colors.length}).map(()=>({is_active:!1,color:new n.Color(0)}))],s={u_time:{value:0},u_color_pressure:{value:new n.Vector2(this._horizontalPressure,this._verticalPressure)},u_wave_frequency_x:{value:this._waveFrequencyX},u_wave_frequency_y:{value:this._waveFrequencyY},u_wave_amplitude:{value:this._waveAmplitude},u_resolution:{value:new n.Vector2(e,o)},u_colors:{value:i},u_colors_count:{value:this._colors.length},u_plane_width:{value:_},u_plane_height:{value:g},u_shadows:{value:this._shadows},u_highlights:{value:this._highlights},u_grain_intensity:{value:this._grainIntensity},u_grain_sparsity:{value:this._grainSparsity},u_grain_scale:{value:this._grainScale},u_grain_speed:{value:this._grainSpeed}},a=new n.ShaderMaterial({uniforms:s,vertexShader:M()+O()+I()+K(),fragmentShader:M()+I()+O()+L()});return a.wireframe=D,a}}function A(t,e,o){const a=e*o/1e6*_*g/1.5,c=e/o,f=Math.sqrt(a*c),h=a/f,l=-_/2,v=Math.min((l+f)/1.5,_/2),y=g/4,z=Math.max((y-h)/2,-g/4),P=-100,S=1e3;t instanceof n.OrthographicCamera?(t.left=l,t.right=v,t.top=y,t.bottom=z,t.near=P,t.far=S,t.updateProjectionMatrix()):t instanceof n.PerspectiveCamera&&(t.aspect=e/o,t.updateProjectionMatrix())}function K(){return` void main() { vUv = uv; v_displacement_amount = cnoise( vec3( u_wave_frequency_x * position.x + u_time, u_wave_frequency_y * position.y + u_time, u_time )); vec3 color; // float t = mod(u_base_color, 100.0); color = u_colors[0].color; // Apply y_offset to the noise coordinates vec2 noise_cord = vUv * u_color_pressure; // Apply the y-offset to shift the pattern vertically (1:1 pixel ratio) // Scale the offset to match the UV coordinate space float scaledOffset = u_y_offset / u_resolution.y; noise_cord.y -= scaledOffset; const float minNoise = .0; const float maxNoise = .9; for (int i = 1; i < u_colors_count; i++) { if(u_colors[i].is_active == 1.0){ float noiseFlow = (1. + float(i)) / 30.; float noiseSpeed = (1. + float(i)) * 0.11; float noiseSeed = 13. + float(i) * 7.; int reverseIndex = u_colors_count - i; float noise = snoise( vec3( noise_cord.x * u_color_pressure.x + u_time * noiseFlow * 2., noise_cord.y * u_color_pressure.y, u_time * noiseSpeed ) + noiseSeed ) - (.1 * float(i)) + (.5 * u_color_blending); noise = clamp(minNoise, maxNoise + float(i) * 0.02, noise); vec3 nextColor = u_colors[i].color; color = mix(color, nextColor, smoothstep(0.0, u_color_blending, noise)); } } v_color = color; vec3 newPosition = position + normal * v_displacement_amount * u_wave_amplitude; gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); v_new_position = gl_Position; } `}function L(){return` float random(vec2 p) { return fract(sin(dot(p, vec2(12.9898,78.233))) * 43758.5453); } float fbm(vec3 x) { float value = 0.0; float amplitude = 0.5; float frequency = 1.0; for (int i = 0; i < 4; i++) { value += amplitude * snoise(x * frequency); frequency *= 2.0; amplitude *= 0.5; } return value; } void main() { vec3 color = v_color; color += pow(v_displacement_amount, 1.0) * u_highlights; color -= pow(1.0 - v_displacement_amount, 2.0) * u_shadows; color = saturation(color, 1.0 + u_saturation); color = color * u_brightness; // Generate grain using fbm vec2 noiseCoords = gl_FragCoord.xy / u_grain_scale; float grain = (u_grain_speed != 0.0) ? fbm(vec3(noiseCoords, u_time * u_grain_speed)) : fbm(vec3(noiseCoords, 0.0)); // Center the grain around zero grain = grain * 0.5 + 0.5; grain -= 0.5; // Add sparsity control grain = (grain > u_grain_sparsity) ? grain : 0.0; // Apply grain intensity grain *= u_grain_intensity; // Add grain to color color += vec3(grain); gl_FragColor = vec4(color, 1.0); } `}const M=()=>` precision highp float; struct Color { float is_active; vec3 color; float value; }; uniform float u_grain_intensity; uniform float u_grain_sparsity; uniform float u_grain_scale; uniform float u_grain_speed; uniform float u_time; uniform float u_wave_amplitude; uniform float u_wave_frequency_x; uniform float u_wave_frequency_y; uniform vec2 u_color_pressure; uniform float u_plane_width; uniform float u_plane_height; uniform float u_shadows; uniform float u_highlights; uniform float u_saturation; uniform float u_brightness; uniform float u_color_blending; uniform int u_colors_count; uniform Color u_colors[5]; uniform vec2 u_resolution; uniform float u_y_offset; varying vec2 vUv; varying vec4 v_new_position; varying vec3 v_color; varying float v_displacement_amount; `,O=()=>` vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); } vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } vec3 fade(vec3 t) { return t*t*t*(t*(t*6.0-15.0)+10.0); } float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); // First corner vec3 i = floor(v + dot(v, C.yyy) ); vec3 x0 = v - i + dot(i, C.xxx) ; // Other corners vec3 g = step(x0.yzx, x0.xyz); vec3 l = 1.0 - g; vec3 i1 = min( g.xyz, l.zxy ); vec3 i2 = max( g.xyz, l.zxy ); // x0 = x0 - 0.0 + 0.0 * C.xxx; // x1 = x0 - i1 + 1.0 * C.xxx; // x2 = x0 - i2 + 2.0 * C.xxx; // x3 = x0 - 1.0 + 3.0 * C.xxx; vec3 x1 = x0 - i1 + C.xxx; vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y // Permutations i = mod289(i); vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); // Gradients: 7x7 points over a square, mapped onto an octahedron. // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) float n_ = 0.142857142857; // 1.0/7.0 vec3 ns = n_ * D.wyz - D.xzx; vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) vec4 x_ = floor(j * ns.z); vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) vec4 x = x_ *ns.x + ns.yyyy; vec4 y = y_ *ns.x + ns.yyyy; vec4 h = 1.0 - abs(x) - abs(y); vec4 b0 = vec4( x.xy, y.xy ); vec4 b1 = vec4( x.zw, y.zw ); //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; vec4 s0 = floor(b0)*2.0 + 1.0; vec4 s1 = floor(b1)*2.0 + 1.0; vec4 sh = -step(h, vec4(0.0)); vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; vec3 p0 = vec3(a0.xy,h.x); vec3 p1 = vec3(a0.zw,h.y); vec3 p2 = vec3(a1.xy,h.z); vec3 p3 = vec3(a1.zw,h.w); //Normalise gradients vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); p0 *= norm.x; p1 *= norm.y; p2 *= norm.z; p3 *= norm.w; // Mix final noise value vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); m = m * m; return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); } // Classic Perlin noise float cnoise(vec3 P) { vec3 Pi0 = floor(P); // Integer part for indexing vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 Pi0 = mod289(Pi0); Pi1 = mod289(Pi1); vec3 Pf0 = fract(P); // Fractional part for interpolation vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); vec4 iy = vec4(Pi0.yy, Pi1.yy); vec4 iz0 = Pi0.zzzz; vec4 iz1 = Pi1.zzzz; vec4 ixy = permute(permute(ix) + iy); vec4 ixy0 = permute(ixy + iz0); vec4 ixy1 = permute(ixy + iz1); vec4 gx0 = ixy0 * (1.0 / 7.0); vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; gx0 = fract(gx0); vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); vec4 sz0 = step(gz0, vec4(0.0)); gx0 -= sz0 * (step(0.0, gx0) - 0.5); gy0 -= sz0 * (step(0.0, gy0) - 0.5); vec4 gx1 = ixy1 * (1.0 / 7.0); vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; gx1 = fract(gx1); vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); vec4 sz1 = step(gz1, vec4(0.0)); gx1 -= sz1 * (step(0.0, gx1) - 0.5); gy1 -= sz1 * (step(0.0, gy1) - 0.5); vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); g000 *= norm0.x; g010 *= norm0.y; g100 *= norm0.z; g110 *= norm0.w; vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); g001 *= norm1.x; g011 *= norm1.y; g101 *= norm1.z; g111 *= norm1.w; float n000 = dot(g000, Pf0); float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); float n111 = dot(g111, Pf1); vec3 fade_xyz = fade(Pf0); vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); return 2.2 * n_xyz; } // YUV to RGB matrix mat3 yuv2rgb = mat3(1.0, 0.0, 1.13983, 1.0, -0.39465, -0.58060, 1.0, 2.03211, 0.0); // RGB to YUV matrix mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722, -0.09991, -0.33609, 0.43600, 0.615, -0.5586, -0.05639); vec3 oklab2rgb(vec3 linear) { const mat3 im1 = mat3(0.4121656120, 0.2118591070, 0.0883097947, 0.5362752080, 0.6807189584, 0.2818474174, 0.0514575653, 0.1074065790, 0.6302613616); const mat3 im2 = mat3(+0.2104542553, +1.9779984951, +0.0259040371, +0.7936177850, -2.4285922050, +0.7827717662, -0.0040720468, +0.4505937099, -0.8086757660); vec3 lms = im1 * linear; return im2 * (sign(lms) * pow(abs(lms), vec3(1.0/3.0))); } vec3 rgb2oklab(vec3 oklab) { const mat3 m1 = mat3(+1.000000000, +1.000000000, +1.000000000, +0.396337777, -0.105561346, -0.089484178, +0.215803757, -0.063854173, -1.291485548); const mat3 m2 = mat3(+4.076724529, -1.268143773, -0.004111989, -3.307216883, +2.609332323, -0.703476310, +0.230759054, -0.341134429, +1.706862569); vec3 lms = m1 * oklab; return m2 * (lms * lms * lms); } `,I=()=>` vec3 saturation(vec3 rgb, float adjustment) { const vec3 W = vec3(0.2125, 0.7154, 0.0721); vec3 intensity = vec3(dot(rgb, W)); return mix(intensity, rgb, adjustment); } float saturation(vec3 rgb) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); vec4 p = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g)); vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; return abs(6.0 * d + e); } // get saturation of a color in values between 0 and 1 float getSaturation(vec3 color) { float max = max(color.r, max(color.g, color.b)); float min = min(color.r, min(color.g, color.b)); return (max - min) / max; } vec3 rgb2hsv(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } `,N=t=>{t.id=F,t.href="https://neat.firecms.co",t.target="_blank",t.style.position="absolute",t.style.display="block",t.style.bottom="0",t.style.right="0",t.style.padding="10px",t.style.color="#dcdcdc",t.style.opacity="0.8",t.style.fontFamily="sans-serif",t.style.fontSize="16px",t.style.fontWeight="bold",t.style.textDecoration="none",t.style.zIndex="10000",t.innerHTML="NEAT"},G=t=>{const e=t.parentElement?.getElementsByTagName("a");if(e){for(let i=0;i<e.length;i++)if(e[i].id===F){N(e[i]);return}}const o=document.createElement("a");N(o),t.parentElement?.appendChild(o)};function U(){const t=new Date,e=t.getMinutes(),o=t.getSeconds();return e*60+o}function V(t=6){const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";let o="";for(let i=0;i<t;i++){const s=Math.floor(Math.random()*e.length);o+=e.charAt(s)}return o}function H(t,e){const o=document.createElement("a");o.download=e,o.href=t,document.body.appendChild(o),o.click(),document.body.removeChild(o)}u.NeatGradient=B,Object.defineProperties(u,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); //# sourceMappingURL=index.umd.js.map