diff options
Diffstat (limited to 'front/src')
| -rw-r--r-- | front/src/app.css | 41 | ||||
| -rw-r--r-- | front/src/app.tsx | 3 | ||||
| -rw-r--r-- | front/src/components/animated_bg.tsx | 114 | ||||
| -rw-r--r-- | front/src/components/navbar.css | 7 | ||||
| -rw-r--r-- | front/src/pages/games.tsx | 2 | ||||
| -rw-r--r-- | front/src/pages/home.tsx | 26 | ||||
| -rw-r--r-- | front/src/pages/projects.tsx | 14 |
7 files changed, 183 insertions, 24 deletions
diff --git a/front/src/app.css b/front/src/app.css index b4086a2..b16cfea 100644 --- a/front/src/app.css +++ b/front/src/app.css @@ -24,6 +24,25 @@ filter: drop-shadow(0 0 2em #673ab8aa); } +/* fade in */ +@keyframes fade-in { + 0% { + opacity: 0; + transform: translateY(1em); + } + 60% { + transform: translateY(-0.2em); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +.main-info > * { + animation: fade-in 0.2s ease-in; +} + .main-info { text-align: center; } @@ -64,7 +83,21 @@ color: #e5c07b; } +.back-shadows { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; + background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, var(--color-bg) 10%, var(--color-bg) 90%, rgba(0, 0, 0, 0) 100%); +} + @media (max-width: 480px) { + .back-shadows { + margin: auto; + max-width: 80%; + } .main-info-title { font-size: 32pt; } @@ -75,6 +108,10 @@ } @media (max-width: 1150px) and (min-width: 480px) { + .back-shadows { + margin: auto; + max-width: 60%; + } .main-info-title { font-size: 42pt; } @@ -85,6 +122,10 @@ } @media (min-width: 1150px) { + .back-shadows { + margin: auto; + max-width: 40%; + } .main-info-title { font-size: 42pt; } diff --git a/front/src/app.tsx b/front/src/app.tsx index 5ba8e6f..ba081c9 100644 --- a/front/src/app.tsx +++ b/front/src/app.tsx @@ -6,6 +6,7 @@ import Home from './pages/home' import { Router, Route, CustomHistory } from 'preact-router'; import Projects from './pages/projects'; import { HashHistory, createHashHistory } from 'history'; +import { AnimatedBg } from './components/animated_bg'; const hashHistoryAdapter = (hashHistory: HashHistory): CustomHistory => { return { @@ -21,6 +22,7 @@ export function App() { return ( <> <Navbar /> + <div class="back-shadows"></div> <div id="app-main"> <Router history={history}> <Route path="/" component={Home} /> @@ -28,6 +30,7 @@ export function App() { <Route path="/games" component={Games} /> <Route path="/projects" component={Projects} /> </Router> + <AnimatedBg /> </div> </> ) 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 ( + <div style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", zIndex: -10 }}> + <Surface width={window.innerWidth} height={window.innerHeight / 2}> + <Node + shader={shaders.letters} + uniforms={{ + t, + color: [42 / 255, 42 / 255, 80 / 255], + tiles: [Math.ceil(window.innerWidth / 32), Math.ceil(window.innerHeight / 64)], + symbol_count: 9, + time: tick / 60 + }} + uniformsOptions={{ + t: { interpolation: "nearest" } + }} /> + </Surface> + </div> + ); +} + +// 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 <C {...this.props} tick={this.state.tick} />; + } + }; +} + +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 { diff --git a/front/src/pages/games.tsx b/front/src/pages/games.tsx index 2ff4eff..6d0d2bd 100644 --- a/front/src/pages/games.tsx +++ b/front/src/pages/games.tsx @@ -11,7 +11,7 @@ export default function Games() { Game Projects </div> <div class="main-info-subtitle"> - my game projects, mostly from game jams + games I've worked on </div> <div class="projects-container"> { diff --git a/front/src/pages/home.tsx b/front/src/pages/home.tsx index 9b29803..df76b84 100644 --- a/front/src/pages/home.tsx +++ b/front/src/pages/home.tsx @@ -9,20 +9,20 @@ export default function Home() { aka Duckonaut, EchoDuck </div> <img src="assets/images/duckpfp.png" class="main-info-image logo grow" /> - </div> - <div class="about-paragraph"> - <p> - Hello! I'm a programmer, game designer, and artist. I'm currently a student at the Warsaw University of - Technology, studying Computer Science. A list of the games I've worked on is in the <a class="games-link" - href="#/games">games</a> section. Other projects I've been a part of are available in the <a class="projects-link" - href="#/projects">projects</a> section. - I also enjoy some lower-level programming and learning about the inner workings of various systems. The main - technologies I use are <span class="highlight">C#</span>, <span class="highlight">Unity</span> - , <span class="highlight">Python</span>, <span class="highlight">Rust</span> and <span class="highlight">C</span>, - although I'm also familiar with <span class="highlight">Godot</span>, <span class="highlight">C++</span> - , <span class="highlight">Java</span> and some <span class="highlight">JavaScript</span> and <span class="highlight">TypeScript</span>. - </p> + <div class="about-paragraph"> + <p> + Hello! I'm a programmer, game designer, and artist. I'm currently a student at the Warsaw University of + Technology, studying Computer Science. A list of the games I've worked on is in the <a class="games-link" + href="#/games">games</a> section. Other projects I've been a part of are available in the <a class="projects-link" + href="#/projects">projects</a> section. + I also enjoy some lower-level programming and learning about the inner workings of various systems. The main + technologies I use are <span class="highlight">C#</span>, <span class="highlight">Unity</span> + , <span class="highlight">Python</span>, <span class="highlight">Rust</span> and <span class="highlight">C</span>, + although I'm also familiar with <span class="highlight">Godot</span>, <span class="highlight">C++</span> + , <span class="highlight">Java</span> and some <span class="highlight">JavaScript</span> and <span class="highlight">TypeScript</span>. + </p> + </div> </div> </> ); diff --git a/front/src/pages/projects.tsx b/front/src/pages/projects.tsx index ed68529..2753f91 100644 --- a/front/src/pages/projects.tsx +++ b/front/src/pages/projects.tsx @@ -13,14 +13,14 @@ export default function Projects() { <div class="main-info-subtitle"> projects that are not games </div> - </div> - <div class="projects-container"> - { - projects.map((project) => ( - Project(project) - )) - } + <div class="projects-container"> + { + projects.map((project) => ( + Project(project) + )) + } + </div> </div> </> ); |
