UNPKG

@firecms/neat

Version:

Beautiful 3D gradients for your website

648 lines (568 loc) 21 kB
import * as i from "three"; const _ = 50, g = 80, W = !0, S = 5, X = new i.Clock(), R = ee(); class oe { _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: n = 4, horizontalPressure: s = 3, verticalPressure: a = 3, waveFrequencyX: c = 5, waveFrequencyY: v = 5, waveAmplitude: f = 3, colors: l, highlights: u = 4, shadows: h = 4, colorSaturation: p = 0, colorBrightness: w = 1, colorBlending: z = 5, grainScale: E = 2, grainIntensity: B = 0.55, grainSparsity: D = 0, grainSpeed: k = 0.1, wireframe: K = !1, backgroundColor: L = "#FFFFFF", backgroundAlpha: U = 1, resolution: V = 1, seed: C, yOffset: G = 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 = n, this.horizontalPressure = s, this.verticalPressure = a, this.waveFrequencyX = c, this.waveFrequencyY = v, this.waveAmplitude = f, this.colorBlending = z, this.grainScale = E, this.grainIntensity = B, this.grainSparsity = D, this.grainSpeed = k, this.colors = l, this.shadows = h, this.highlights = u, this.colorSaturation = p, this.colorBrightness = w, this.wireframe = K, this.backgroundColor = L, this.backgroundAlpha = U, this.yOffset = G, this.sceneState = this._initScene(V); let b = C !== void 0 ? C : $(); const q = () => { const { renderer: d, camera: m, scene: y, meshes: x } = this.sceneState; Math.floor(b * 10) % 5 === 0 && Z(o), d.setClearColor(this._backgroundColor, this._backgroundAlpha), x.forEach((r) => { const j = this._ref.width, Y = this._ref.height, H = [ ...this._colors.map((P) => { let F = new i.Color(); return F.setStyle(P.color, ""), { is_active: P.enabled, color: F, influence: P.influence }; }), ...Array.from({ length: S - this._colors.length }).map(() => ({ is_active: !1, color: new i.Color(0) })) ]; b += X.getDelta() * this._speed, r.material.uniforms.u_time.value = b, r.material.uniforms.u_resolution = { value: new i.Vector2(j, Y) }, r.material.uniforms.u_color_pressure = { value: new i.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: H }, r.material.uniforms.u_colors_count = { value: S }, 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; }), d.render(y, m), this.requestRef = requestAnimationFrame(q); }, T = () => { const { renderer: d } = this.sceneState, m = d.domElement, y = m.clientWidth, x = m.clientHeight; this.sceneState.renderer.setSize(y, x, !1), A(this.sceneState.camera, y, x); }; this.sizeObserver = new ResizeObserver((d) => { T(); }), this.sizeObserver.observe(o), q(); } 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), te(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 * 0.04; } set waveFrequencyY(e) { this._waveFrequencyY = e * 0.04; } set waveAmplitude(e) { this._waveAmplitude = e * 0.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, n = this._ref.height, s = new i.WebGLRenderer({ alpha: !0, preserveDrawingBuffer: !0, canvas: this._ref }); s.setClearColor(16711680, 0.5), s.setSize(o, n, !1); const a = [], c = new i.Scene(), v = this._buildMaterial(o, n), f = new i.PlaneGeometry(_, g, 240 * e, 240 * e), l = new i.Mesh(f, v); l.rotation.x = -Math.PI / 3.5, l.position.z = -1, a.push(l), c.add(l); const u = new i.OrthographicCamera(0, 0, 0, 0, 0, 0); return u.position.z = 5, A(u, o, n), { renderer: s, camera: u, scene: c, meshes: a, resolution: e }; } _buildMaterial(e, o) { const n = [ ...this._colors.map((c) => ({ is_active: c.enabled, color: new i.Color(c.color), influence: c.influence })), ...Array.from({ length: S - this._colors.length }).map(() => ({ is_active: !1, color: new i.Color(0) })) ], s = { u_time: { value: 0 }, u_color_pressure: { value: new i.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 i.Vector2(e, o) }, u_colors: { value: n }, 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 i.ShaderMaterial({ uniforms: s, vertexShader: I() + M() + O() + J(), fragmentShader: I() + O() + M() + Q() }); return a.wireframe = W, a; } } function A(t, e, o) { const a = e * o / 1e6 * _ * g / 1.5, c = e / o, v = Math.sqrt(a * c), f = a / v, l = -_ / 2, u = Math.min((l + v) / 1.5, _ / 2), h = g / 4, p = Math.max((h - f) / 2, -g / 4), w = -100, z = 1e3; t instanceof i.OrthographicCamera ? (t.left = l, t.right = u, t.top = h, t.bottom = p, t.near = w, t.far = z, t.updateProjectionMatrix()) : t instanceof i.PerspectiveCamera && (t.aspect = e / o, t.updateProjectionMatrix()); } function J() { 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 Q() { 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 I = () => ` 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; `, M = () => ` 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); } `, O = () => ` 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 = R, 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"; }, Z = (t) => { const e = t.parentElement?.getElementsByTagName("a"); if (e) { for (let n = 0; n < e.length; n++) if (e[n].id === R) { N(e[n]); return; } } const o = document.createElement("a"); N(o), t.parentElement?.appendChild(o); }; function $() { const t = new Date(), e = t.getMinutes(), o = t.getSeconds(); return e * 60 + o; } function ee(t = 6) { const e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let o = ""; for (let n = 0; n < t; n++) { const s = Math.floor(Math.random() * e.length); o += e.charAt(s); } return o; } function te(t, e) { const o = document.createElement("a"); o.download = e, o.href = t, document.body.appendChild(o), o.click(), document.body.removeChild(o); } export { oe as NeatGradient }; //# sourceMappingURL=index.es.js.map