diff --git a/.vscode/settings.json b/.vscode/settings.json index 48032d3..bc3732e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,24 @@ { "cSpell.words": [ + "EEPROM", "Glsl", "andras", "decla", "favicons", "forex", "froms", + "leds", + "mesmerising", + "optimisations", + "optimised", + "organiser", + "realised", "schmelczer", + "serialisation", + "synchronised", + "tabindex", + "utilised", + "utilising", "webm", "webp" ] diff --git a/package.json b/package.json index 91ff151..bdd2f08 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "sass": "^1.26.10", "sass-loader": "^8.0.2", "sharp": "^0.23.4", + "string-replace-loader": "^2.3.0", "style-loader": "^1.2.1", "terser-webpack-plugin": "^2.3.8", "ts-loader": "^6.2.2", diff --git a/src/data/ad-astra.ts b/src/data/ad-astra.ts new file mode 100644 index 0000000..87eea44 --- /dev/null +++ b/src/data/ad-astra.ts @@ -0,0 +1,41 @@ +import adAstraPoster from '../static/media/ad_astra.jpg?format=jpg'; +import adAstraMp4 from '../static/media/ad_astra_720.mp4'; +import adAstraWebM from '../static/media/ad_astra_720.webm'; + +import { GitHub } from './shared'; +import { last } from '../helper/last'; +import { Video } from '../page/basics/video/video'; + +export const adAstraTimelineElement = { + title: `Gaming on an ATtiny85`, + date: `2020 Spring`, + figure: new Video({ + poster: last(adAstraPoster.images)!.path, + mp4: adAstraMp4, + webm: adAstraWebM, + }), + description: ` + A simple game engine with a sample game set in space. The greatest challenge was to overcome + the very limited resources of the hardware, this was also the most rewarding part. + `, + more: [ + ` + For reducing complexity while maintaining performance, a balance had to be found between object-oriented + and structural programming. For example, a simple prototype-based inheritance is used for the game objects; + meanwhile, an optimised SIMD utilising low-level driver is used for rendering to the display. + I think, the codebase is quite readable and at the same time also fast, with the maximum frame times + being between 15 and 20 milliseconds at a clock speed of 8 MHz. That means, it runs quite stably at 50-60 FPS. + `, + ` + As for the hardware, it is quite simple. Aside from the ATtiny85V, a D096-12864-SPI7 display is used for + output and a TSOP4838 for input. The circuit runs on 3.3V, so a regulator is also needed. It uses a current + of 8mA to 11mA on full brightness and around 1.5mA on standby mode. + `, + ` + There is also fault-tolerant persistent data storage utilising the built-in EEPROM. + For creating sprites (which are also stored in EEPROM), I made a tool to convert PNG-s into C array definitions. + This can also be found on GitHub along with the entire project. + `, + ], + links: [new GitHub('https://github.com/schmelczerandras/ad_astra')], +}; diff --git a/src/data/city-simulation.ts b/src/data/city-simulation.ts new file mode 100644 index 0000000..3cb0377 --- /dev/null +++ b/src/data/city-simulation.ts @@ -0,0 +1,38 @@ +import citySimulationPoster from '../static/media/simulation.jpg?format=jpg'; +import citySimulationWebM from '../static/media/simulation.webm'; +import citySimulationMp4 from '../static/media/simulation.mp4'; + +import { Video } from '../page/basics/video/video'; +import { last } from '../helper/last'; + +export const citySimulationTimelineElement = { + date: `2018 July - August`, + title: `City simulation`, + figure: new Video({ + poster: last(citySimulationPoster.images)!.path, + mp4: citySimulationMp4, + webm: citySimulationWebM, + }), + description: `Simulating a city where car crashes are more frequent than usual.`, + more: [ + ` + The state of the traffic lights can be changed through a REST API. + Drivers follow the instructions of the traffic lights, so if a mistake is made, + there will be collisions. There is also support for displaying tweets on a HUD. + `, + ` + This was created for a cybersecurity challenge. With the help of this program + the contestants could instantly see the effect of their work. + `, + ` + The most interesting aspect of this project was building it in a server-client architecture. + Every decision of the agents is calculated server-side. The real challenge was broadcasting + these decisions in a fault-tolerant way using minimal bandwidth. + `, + ` + It is made with Unity using C# as the scripting language. + The models and animations were also made by me using Blender. + `, + ], + links: [], +}; diff --git a/src/data/colors.ts b/src/data/colors.ts new file mode 100644 index 0000000..d109e4c --- /dev/null +++ b/src/data/colors.ts @@ -0,0 +1,29 @@ +import colourJpeg from '../static/media/color.jpg?format=jpg'; +import colourWebP from '../static/media/color.jpg?format=webp'; + +import { Image } from '../page/basics/image/image'; +import { Open } from './shared'; + +export const colorsTimelineElement = { + date: `2018 June`, + title: `Photo colour grader`, + figure: new Image(colourWebP, colourJpeg, `a picture of the app`), + description: `An innovative (at least I thought so) colour grader web application.`, + more: [ + ` + The most noteworthy feature of this application is the colour selector UI. + This program is only intended as a proof-of-concept, I would have liked to + experiment with some ideas and this was the outcome. + `, + ` + You can select some colours and then apply transformations to the other colours as a + function of their distance to the selected colour. + `, + ` + By clicking on a coloured circle you can change its settings. + New circles can be created by clicking in the large circle + (and they can also be moved by drag & drop). + `, + ], + links: [new Open('color.schmelczer.dev')], +}; diff --git a/src/data/declared.ts b/src/data/declared.ts new file mode 100644 index 0000000..e88d710 --- /dev/null +++ b/src/data/declared.ts @@ -0,0 +1,40 @@ +import declaredJpeg from '../static/media/decla-red.png?format=jpg'; +import declaredWebP from '../static/media/decla-red.png?format=webp'; +import thesis from '../static/media/andras_schmelczer_thesis.pdf'; + +import { Preview } from '../page/basics/preview/preview'; +import { GitHub, Thesis, Open } from './shared'; + +export const declaredTimelineElement = { + title: `Multiplayer game`, + date: `2020 Autumn`, + figure: new Preview( + declaredWebP, + declaredJpeg, + 'https://decla.red', + 'The website of the video game' + ), + description: ` + Using SDF-2D (my ray tracing graphics library), I created a conquest-style multiplayer browser game. + It even runs on mobiles. + `, + more: [ + ` + The scene is set in space, two teams have to conquer small planets, while they can also shoot at the other team. + Points are given based on the number of planets controlled, and the first team which reaches a predefined score wins. + `, + ` + As for the communication, a server-client architecture is used. Messaging is provided by Socket.IO and + a custom serialisation solution. + `, + ` + This (along with SDF-2D) was my BSc thesis project, so more in-depth information about them + can be found in my thesis linked below. + `, + ], + links: [ + new GitHub('https://github.com/schmelczerandras/decla.red'), + new Thesis(thesis), + new Open('https://decla.red'), + ], +}; diff --git a/src/data/forex.ts b/src/data/forex.ts new file mode 100644 index 0000000..ee06a88 --- /dev/null +++ b/src/data/forex.ts @@ -0,0 +1,30 @@ +import forexMp4 from '../static/media/forex.mp4'; +import forexWebM from '../static/media/forex.webm'; +import { Video } from '../page/basics/video/video'; + +export const forexTimelineElement = { + title: `Predicting foreign exchange rates`, + date: `2019 Autumn`, + figure: new Video({ + mp4: forexMp4, + webm: forexWebM, + shouldActLikeGif: true, + }), + description: ` + From the animation, we can see that my implementation does a somewhat acceptable job at + predicting (blue graph) the EUR/USD rates (green graph). + `, + more: [ + ` + In a nutshell, the algorithm (written in Python using NumPy, SciPy, and Flask) + predicts in the frequency domain. The steps are the following: smoothing the input values, + differentiating, applying a short-time Fourier-transformation with overlapped (and Hanning-windowed) windows, + extrapolating and then applying the inverse of these transformations to the resulting values. + `, + ` + Of course, there is still plenty of room for improvement, but even with this simple algorithm + a mostly profitable trading strategy is viable. In my free time I may put more work into it. + `, + ], + links: [], +}; diff --git a/src/data/leds.ts b/src/data/leds.ts new file mode 100644 index 0000000..0c482f2 --- /dev/null +++ b/src/data/leds.ts @@ -0,0 +1,33 @@ +import ledPoster from '../static/media/led.jpg?format=jpg'; +import ledMp4 from '../static/media/led.mp4'; +import ledWebM from '../static/media/led.webm'; + +import { last } from '../helper/last'; +import { Video } from '../page/basics/video/video'; + +export const ledsTimelineElement = { + date: `2016 spring`, + title: `Lights synchronised to music`, + figure: new Video({ + poster: last(ledPoster.images)!.path, + mp4: ledMp4, + webm: ledWebM, + }), + description: ` + A full stack application with a built-in music player + the output of which controls the colour of a couple of RGB LED strips. + `, + more: [ + ` + This was my first non-trivial project which got finished. Obviously, + it is rather far from perfect, but I am still proud that I was able + to build it on my own. + `, + ` + The backend logic is written in Python, the FFT implementation is provided by NumPy. + A quite simple frontend for accessing the music player and changing + the settings also got built using vanilla web development technologies. + `, + ], + links: [], +}; diff --git a/src/data/my-notes.ts b/src/data/my-notes.ts new file mode 100644 index 0000000..7a78e86 --- /dev/null +++ b/src/data/my-notes.ts @@ -0,0 +1,24 @@ +import myNotesJpeg from '../static/media/my-notes.png?format=jpg'; +import myNotesWebP from '../static/media/my-notes.png?format=webp'; + +import { Image } from '../page/basics/image/image'; +import { GitHub } from './shared'; + +export const myNotesTimelineElement = { + date: `2019 November`, + title: `My Notes`, + figure: new Image(myNotesWebP, myNotesJpeg, `two screenshots of the application`), + description: `A minimalist note organiser and editor powered by Markwon.`, + more: [ + ` + This is a basic android app for creating and filtering markdown notes + (based on #hashtags). It was my first exposure to Android development. + `, + ` + All in all, it is not a tremendous engineering feat, but at least it's usable. + The knowledge gained while working on it was the more significant outcome of this + adventure. + `, + ], + links: [new GitHub('https://github.com/schmelczerandras/my-notes')], +}; diff --git a/src/data/nuclear-editor.ts b/src/data/nuclear-editor.ts new file mode 100644 index 0000000..f208367 --- /dev/null +++ b/src/data/nuclear-editor.ts @@ -0,0 +1,28 @@ +import processSimulatorInputJpeg from '../static/media/process-simulator-input.jpg?format=jpg'; +import processSimulatorInputWebP from '../static/media/process-simulator-input.jpg?format=webp'; + +import { Image } from '../page/basics/image/image'; + +export const nuclearEditorTimelineElement = { + date: `2018 October - November`, + title: `Graph editing application`, + figure: new Image( + processSimulatorInputWebP, + processSimulatorInputJpeg, + `a picture of the simulator's UI` + ), + description: ` + An intuitive editor to create and edit input for the nuclear facility simulator. + `, + more: [ + ` + Nodes can be moved with drag & drop gestures. + Editing the parameters of elements can be done on the right panel. + `, + ` + The UI is built with JavaFX. The output can be exported as JSON or + directly uploaded to the simulation backend. + `, + ], + links: [], +}; diff --git a/src/data/nuclear.ts b/src/data/nuclear.ts new file mode 100644 index 0000000..eeb484e --- /dev/null +++ b/src/data/nuclear.ts @@ -0,0 +1,39 @@ +import processSimulatorJpeg from '../static/media/process-simulator.jpg?format=jpg'; +import processSimulatorWebP from '../static/media/process-simulator.jpg?format=webp'; + +import { Image } from '../page/basics/image/image'; + +export const nuclearTimelineElement = { + date: `2018 October - November`, + title: `Simulating the cooling system of a nuclear facility`, + figure: new Image( + processSimulatorWebP, + processSimulatorJpeg, + `a screenshot of the simulator` + ), + description: ` + The temperatures and flow velocities are dynamically calculated in a fluid-based + cooling system based on a simple model. + `, + more: [ + ` + A simulated system can contain reactors (heaters), coolers, pumps, heat exchangers, + drains, sources, and of course, pipes. With this, simple yet believable configurations + can be defined. The aim of the project was to create a cheaply calculated and + (for layman) a convincingly looking simulation. + `, + ` + The algorithm takes advantages of graphs and matrices to get to a next time frame. First, + water flows are distributed by traversing the graph of pipes. Then a matrix is populated + with the relations of the nodes (based on the water flow between them). + After considering the base temperatures and heaters, the matrix is solved resulting in the + current temperature of each node. This can be iteratively continued. + `, + ` + Python is used for the backend along with Flask and NumPy. A REST API facilitates + the communication between the layers. For rendering on the frontend, a HTML5 canvas + is utilised. + `, + ], + links: [], +}; diff --git a/src/data/photos.ts b/src/data/photos.ts new file mode 100644 index 0000000..42f036f --- /dev/null +++ b/src/data/photos.ts @@ -0,0 +1,13 @@ +import photosJpeg from '../static/media/photos.jpg?format=jpg'; +import photosWebP from '../static/media/photos.jpg?format=webp'; + +import { Image } from '../page/basics/image/image'; +import { Open } from './shared'; + +export const photosTimelineElement = { + date: `2016 summer`, + title: `Photos`, + figure: new Image(photosWebP, photosJpeg, `a picture of the website`), + description: `A simple web page where you can view my photos.`, + links: [new Open('https://photo.schmelczer.dev')], +}; diff --git a/src/data/platform-game.ts b/src/data/platform-game.ts new file mode 100644 index 0000000..46b464e --- /dev/null +++ b/src/data/platform-game.ts @@ -0,0 +1,21 @@ +import platformJpeg from '../static/media/platform.png?format=jpg'; +import platformWebP from '../static/media/platform.png?format=webp'; + +import { Image } from '../page/basics/image/image'; + +export const platformGameTimelineElement = { + date: `2017 autumn`, + title: `Platform game`, + figure: new Image(platformWebP, platformJpeg, `a picture of the app`), + description: `A 3D game written in C with the help of SDL 1.2 (I haven't heard of GPU programming at the time).`, + more: [ + ` + The maps are randomly generated and fully destroyable. + The player is getting chased by flying enemies. Overall, I find it a really enjoyable game. + `, + ` + I did this as a homework for my Basics of Programming course. + `, + ], + links: [], +}; diff --git a/src/data/sdf2d.ts b/src/data/sdf2d.ts new file mode 100644 index 0000000..8312ae1 --- /dev/null +++ b/src/data/sdf2d.ts @@ -0,0 +1,41 @@ +import sdf2dJpeg from '../static/media/sdf2d.png?format=jpg'; +import sdf2dWebP from '../static/media/sdf2d.png?format=webp'; + +import { Preview } from '../page/basics/preview/preview'; +import { GitHub, Open, NPM } from './shared'; + +export const sdf2dTimelineElement = { + title: `2D ray tracing`, + date: `2020 Autumn`, + figure: new Preview( + sdf2dWebP, + sdf2dJpeg, + 'https://sdf2d.schmelczer.dev', + 'A webpage showcasing the SDF-2D project.' + ), + description: ` + I created the SDF-2D library for efficiently rendering 2D scenes using ray tracing. + My solution relies on signed distance fields (SDF-s), it supports both WebGL and WebGL2, + and is an easily reusable and extendible NPM package. + `, + more: [ + ` + A multitude of optimisations were needed to achieve real-time performance even on low-end mobile devices. + These include deferred shading, tile-based rendering, and dynamic shader generation to eliminate unnecessary + instructions. + `, + ` + The result is a reusable library written in TypeScript with a — subjectively — simple and elegant API. + For more information please check out the GitHub repository or the NPM package itself. Or simply enjoy the + mesmerising demo scenes. + `, + ` + Creating this library package is also covered in my thesis (available above). + `, + ], + links: [ + new GitHub('https://github.com/schmelczerandras/sdf-2d'), + new NPM('https://www.npmjs.com/package/sdf-2d'), + new Open('https://sdf2d.schmelczer.dev'), + ], +}; diff --git a/src/data/shared.ts b/src/data/shared.ts new file mode 100644 index 0000000..c8ec956 --- /dev/null +++ b/src/data/shared.ts @@ -0,0 +1,11 @@ +import { ImageAnchorFactory } from '../page/basics/image-anchor/image-anchor'; + +import githubIcon from '../static/icons/github.svg'; +import openIcon from '../static/icons/open.svg'; +import cvIcon from '../static/icons/cv.svg'; +import packageIcon from '../static/icons/package.svg'; + +export const GitHub = ImageAnchorFactory(githubIcon, 'Open on GitHub'); +export const NPM = ImageAnchorFactory(packageIcon, 'Open on npm'); +export const Open = ImageAnchorFactory(openIcon, 'Open in new tab'); +export const Thesis = ImageAnchorFactory(cvIcon, 'Download thesis'); diff --git a/src/page/basics/text/text.html.ts b/src/page/basics/text/text.html.ts deleted file mode 100644 index 906f48c..0000000 --- a/src/page/basics/text/text.html.ts +++ /dev/null @@ -1,6 +0,0 @@ -import './text.scss'; -import { html } from '../../../types/html'; - -export const generate = (text: string): html => ` -
${text}
-`; diff --git a/src/page/basics/text/text.scss b/src/page/basics/text/text.scss deleted file mode 100644 index ff1c0ba..0000000 --- a/src/page/basics/text/text.scss +++ /dev/null @@ -1,6 +0,0 @@ -@use '../../../style/mixins' as *; - -.text { - @include main-font(); - text-align: left; -} diff --git a/src/page/basics/text/text.ts b/src/page/basics/text/text.ts deleted file mode 100644 index c64c422..0000000 --- a/src/page/basics/text/text.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { PageElement } from '../../page-element'; -import { createElement } from '../../../helper/create-element'; -import { generate } from './text.html'; - -export class Text extends PageElement { - public constructor(text: string) { - super(createElement(generate(text))); - } -} diff --git a/src/page/basics/video/video.html.ts b/src/page/basics/video/video.html.ts index 4f12bd2..d691a26 100644 --- a/src/page/basics/video/video.html.ts +++ b/src/page/basics/video/video.html.ts @@ -3,20 +3,22 @@ import { url } from '../../../types/url'; import { html } from '../../../types/html'; export const generate = ({ - poster, - options, webm, mp4, + poster, + shouldActLikeGif, container, }: { - poster?: url; - options?: string; webm: url; mp4: url; + poster?: url; + shouldActLikeGif?: boolean; container?: boolean; }): html => ` ${container === undefined || container ? `