From d6c36c47f855ac3fd998cedc422a6d91ecbf10f8 Mon Sep 17 00:00:00 2001 From: Stanisław Zagórowski Date: Thu, 5 Oct 2023 20:52:47 +0200 Subject: front: awesome background --- front/src/components/animated_bg.tsx | 114 +++++++++++++++++++++++++++++++++++ front/src/components/navbar.css | 7 ++- 2 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 front/src/components/animated_bg.tsx (limited to 'front/src/components') diff --git a/front/src/components/animated_bg.tsx b/front/src/components/animated_bg.tsx new file mode 100644 index 0000000..6a8ab3a --- /dev/null +++ b/front/src/components/animated_bg.tsx @@ -0,0 +1,114 @@ +import { Shaders, Node, GLSL } from "gl-react"; +import { Surface } from "gl-react-dom"; +import React from "preact/compat"; +import { PropsWithChildren } from "preact/compat"; + +const shaders = Shaders.create({ + letters: { + frag: GLSL` +precision highp float; +varying vec2 uv; +uniform vec3 color; +uniform sampler2D t; +uniform float time; +uniform vec2 tiles; +uniform float symbol_count; + +vec2 map_to_symbol_uv(vec2 image_coord, float symbol_index) { + float symbol_width = 1.0 / symbol_count; + float symbol_height = 1.0; + float symbol_x = symbol_index * symbol_width; + return vec2(symbol_x + image_coord.x * symbol_width, image_coord.y * symbol_height); +} + +vec2 tile_index(vec2 p, vec2 tiles) { + return vec2(floor(p.x * tiles.x), floor(p.y * tiles.y)); +} + +vec2 tilefy (vec2 p, vec2 tiles) { + return vec2(fract(p.x * tiles.x), fract(p.y * tiles.y)); +} + +float randf(float n) { + return fract(sin(n) * 43758.5453123); +} + +void main() { + vec2 tile = tile_index(uv, tiles); + float tilerand = randf(tile.x + tile.y * tiles.x); + float v = tilerand + randf(floor(tilerand * time)); + float diff = fract(tilerand * time); + float s = floor(v * 9.0); + vec2 tp = tilefy(uv, tiles); + vec2 tp_center = vec2(0.5, 0.5); + float d = distance(tp, tp_center); + float scale = min(sin(diff * 3.1415) * 1.2, 1.0); + tp = tp_center + (tp - tp_center) / scale; + if (tp.x < 0.0 || tp.x > 1.0 || tp.y < 0.0 || tp.y > 1.0) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + vec2 p = map_to_symbol_uv(tp, mod(s, symbol_count)); + vec4 c = texture2D(t, p); + c.rgb *= color; + c.a *= uv.y * 4.0; + gl_FragColor = vec4(c.rgb * c.a, c.a); +} +` + } +}); + +const fps = 60; + +const AnimatedBgInternal = ({ tick }: { tick: number }) => { + const t = "/assets/images/symbols.png"; + + return ( +
+ + + +
+ ); +} + +// a higher order component that provides a tick prop +// that updates every 1/refreshRate seconds +// +// accepts a JSX component as an argument +const timeLoop = ( + C: (props: PropsWithChildren<{ tick: number }>) => React.JSX.Element, + { refreshRate }: { refreshRate: number } +) => { + return class TimeLoop extends React.Component { + interval: any; + state = { tick: 0 }; + + componentDidMount() { + this.interval = setInterval(() => { + this.setState({ tick: this.state.tick + 1 }); + }, 1000 / refreshRate); + } + + componentWillUnmount() { + clearInterval(this.interval); + } + + render() { + return ; + } + }; +} + +export const AnimatedBg = timeLoop(AnimatedBgInternal, { refreshRate: fps }); diff --git a/front/src/components/navbar.css b/front/src/components/navbar.css index 466fdd6..9120052 100644 --- a/front/src/components/navbar.css +++ b/front/src/components/navbar.css @@ -1,7 +1,7 @@ /* on big screens, navbar is fixed to the top of the screen */ .navbar-container { position: fixed; - background-color: var(--color-bg); + /* gradient from top to bottom, full to transparent */ top: 0; width: 100%; z-index: 9999; @@ -16,11 +16,12 @@ } .navbar { - margin-top: 20pt; - margin-bottom: 12pt; + padding-top: 20pt; + padding-bottom: 12pt; align-items: center; justify-content: center; align-self: center; + background: linear-gradient(to bottom, var(--color-bg) 0%, var(--color-bg) 75%, rgba(0, 0, 0, 0) 100%); } .navbar-icon { -- cgit v1.3.1