🔴 Live demo → https://wms.damian-z.uk/
A warehouse management system covering the full inbound → storage → outbound cycle: product and location master data, lot and expiry tracking, multi-dimensional location capacity, planned putaway and picking, an immutable stock-movement ledger, and an analytics dashboard.
The backend is an ASP.NET Core (.NET 10) Web API built with a clean, layered architecture. The frontend is a Vue 3 single-page app. Data is stored in PostgreSQL.
Storage / Quarantine / Returns), temperature zone (Ambient / Chilled / Frozen), capacity in three dimensions (units / weight / volume, each capped independently, with the most restrictive one deciding), mixed-SKU and mixed-lot rules, active and blocked states, and preferred products per location.Draft → Putaway → Completed, cancellable from Draft or Putaway.PreferredLocation, ConsolidateSameLot, ConsolidateSameSku, Proximity, NearestEmpty, NearestAvailable.Draft → Picking → Completed, cancellable.FEFO (first-expired), FIFO, LIFO, LeastQuantity, plus a Manual override.StockMovement record, created as a side effect through domain events. This gives a complete, append-only audit trail.Admin, Manager, Worker. All endpoints require authentication by default, and write operations require the Admin or Manager role.A job-offer aggregator for the Belgian market. A set of scrapers collects postings from five portals, stores them in a shared database with deduplication and shows them in a single panel with filters. Runs start automatically on a schedule managed from the app, or manually with one button.
A commissioned project, deployed on the client's server (OVHCloud) as a set of Docker containers.
The backend is a FastAPI service (SQLAlchemy + Pydantic, SQLite, Alembic migrations). The frontend is a Vue 3 single-page app with TypeScript and PrimeVue.
source:external_id key with a UNIQUE index, so repeated runs only add new postings.docker compose up. The database and the positions dictionary live in a volume, so rebuilding images leaves them untouched, and the schema is created by migrations executed on API startup.A portfolio website template built on the Angular framework. The application has no backend: all content comes from files in the public/assets directory, so creating your own portfolio comes down to replacing them, without digging into the source code. The whole thing is built as a static site (SSG), meaning every page in every language is rendered to finished HTML at build time and can be served from a CDN, with no application server at all.
Structured data (profile, experience, projects, technologies, site settings) is described in JSON files, while longer workplace and project descriptions live in Markdown files, one per language.
outputMode: static mode produces static HTML for every route and every language. Search engines and link previews get finished content instead of an empty <app-root>, and in the browser the page hydrates into a full SPA. The JSON data and Markdown descriptions fetched at build time are embedded into the resulting HTML, so the browser never fetches them a second time./pl, /en), and each language version has its own prerendered HTML. Interface texts come from translation files (@ngx-translate), and the list of available languages from the site configuration. On the root address the language is taken from the visitor's earlier choice, and when there is none, from the browser preferences. The switcher in the navigation bar changes the language without a reload and without leaving the current page.canonical link and a full set of hreflang links to its language versions (together with x-default), and the lang attribute on <html> matches the content being shown. The CV download page is excluded from indexing.body element, with smooth color transitions. The choice is remembered and applied before the page is first painted, so there is no flash of the other theme on load.tools/generate-thumbnails.py script (Pillow, OpenCV) creates optimized JPEG thumbnails for images and from the first frame of videos, following the thumb_<name>.jpg naming convention.technologies.json, and labels without an entry get a default color.IntersectionObserver; each element animates only once.A desktop application for monitoring the in-game chat in Metin2. Chat is read purely from the screen: the game window is captured every 100 ms and the text is recognized by my own pixel-based OCR algorithm. The application doesn't interfere with the game process, meaning no client files are modified, no memory is read and no code is injected.
The client is a Blazor Hybrid app (.NET MAUI, .NET 10) with a MudBlazor UI. Screen capture is implemented for Windows (P/Invoke into user32/gdi32: GetDC + BitBlt over the client area of the selected window). The backend is an ASP.NET Core Web API with a PostgreSQL database.
[name]) out as separate objects within a messageInstead of an off-the-shelf OCR engine I used bitwise pattern matching, which fits the game's fixed raster font well:
charset.bmp plus the character list in charset.txt) is scanned column by column. Every glyph is encoded as a UInt128 mask and stored in a two-way dictionary (mask <-> character).UInt128 buffer (|= with a bit shift), and an empty column ends the glyph and triggers a dictionary lookup.Private servers differ in font, chat colors, message format, channel count, server start hour and boss list (name, count, respawn time).
{Channel}, {Player} and {Boss} placeholders and compiled into regular expressions with named groups, from which the kill details are pulled out.ASP.NET Core Minimal API (.NET 10), EF Core + PostgreSQL, validation via FluentValidation.
A 2D game engine written in C++ with a graphical editor: an OpenGL renderer, an Entity Component System (EnTT), physics simulation (Box2D), native scripting and a custom networking module built on GameNetworkingSockets.
The core architecture is based on the open-source version of the Hazel engine, but I made a lot of changes and added my own solutions. The biggest one is the networking module, which I wrote entirely myself. It's a hobby project at an early stage, not meant for commercial game production; development is currently on hold.
The networking module was built for my master's thesis. In it I studied how network latency affects the quality of the gameplay simulation, and more specifically: how different parameter values of the client-side prediction algorithm translate into the frequency and scale of desynchronization.
The project is configured with Premake5 (Windows, Visual Studio) and builds in three configurations: Debug, Release (with the editor) and Distribution, an editor-free build that serves as the game runtime.
The engine was previously developed under the name Proton2D. The whole git history lives in the old repository https://github.com/Damian-Zuk/proton2d.
TextureAtlas, Sprite), 9-slice scaling and atlas-based animations.Scene wraps the EnTT registry. Entity is a pair of an identifier and a scene pointer, and every object gets a UUID.AppScript > GameScript > EntityScript (application, game mode and single object logic), a factory that creates scripts by class name and a registration macro.REGISTER_FIELD macro show up in the inspector and are serialized together with the scene. Supported types are scalars, vectors, strings and any trivially copyable data.REPLICATED_FIELD is synchronized over the network automatically, optionally with a callback invoked when a new value arrives.Rigid bodies, box and circle colliders with material parameters and collision filters, sensors, contact listening with a callback into the script, and revolute joints (attaching an object to its parent).
A client-server architecture with a fully authoritative server, running as a listen server, a dedicated server or a client. All communication goes through a custom binary stream (the header is written back once the payload size is known), and every value read is checked against the remaining buffer size. An inconsistent packet disconnects the client instead of reading out of bounds.
PositionX, PositionY, ScaleX, ScaleY, Rotation), and changes to script fields are detected with a CRC32 checksum computed per client. An object with nothing to report is rolled back out of the stream.The synchronization method is set per object in the inspector, together with the reconciliation and teleport thresholds and the correction duration:
A Python CLI tool that generates a vulnerability (CVE) report for IoT devices. It takes a manually prepared device list in JSON format (model, firmware version, MAC address) and/or network scans made with Nmap (XML). For every identified piece of software, that is the firmware, services on open ports and the operating system, the script queries the NIST NVD database and attaches the vulnerabilities it finds to the output report.
Built for the "Security of IoT Systems" course at Rzeszów University of Technology.
devices.json). Manually entered data forms the base of the report and takes precedence over scan data.nmap -A -oX). Hosts are matched to listed devices by MAC address, and unknown ones go into the report as new entries. From a scan the tool pulls the IPv4 address, the vendor (from the MAC), ports in the open state together with their services, and the OS detection result.model + version, product + version, OS name + family + version). Identifiers in the older CPE 2.2 format are converted to CPE 2.3.cpeName queries. If no CPE could be resolved for a device, a keyword search is used instead and the CPE is filled in from the first matching vulnerability.vulnerabilities section.The report is an array of devices, and each entry contains:
firmware, service (keyed by product version) and os (keyed by family version). Each category has the total number of CVEs found and their list, where a single entry carries the CVE identifier, publication date, description, the CVSS metric used, the numeric score and the severity level (LOW / MEDIUM / HIGH / CRITICAL).config.ini)linux, android). For those the number of hits is so large that the result wouldn't be useful anyway, so the report only records a note about the skipped check.A static report-viewer.html page, no backend and no dependencies. The JSON file is loaded via drag and drop. Devices are shown as collapsible panels, severity levels have their own colors, and CVE and CPE identifiers link to the corresponding NVD pages. The same view also handles the input device list, since it has the exact same structure.
versionEndIncluding) are not analyzed, so a vulnerability described by a range may go undetected.A student project in which Ansible automates the configuration of virtual machines, installation of system packages and deployment of a simple LAMP application.
Everything runs in the AWS cloud: the control node and the managed web servers sit on separate instances. Playbooks are executed through Ansible Semaphore, a graphical interface for Ansible. It lets you run tasks from the browser, set up schedules, keep access keys in one place and browse the run history together with logs.
A big part of the project was documenting the whole setup: from preparing the instances and SSH access, through installing and configuring Semaphore, to describing how each role works. The repository contains Ansible files only: playbooks, roles and the inventory.
admin list (with a set UID and description).authorized_keys./etc/sudoers.memory_limit in the PHP configuration to 256 MB.posts table if it doesn't exist yet./var/www, replacing files only when changes are detected.config.php from a Jinja2 template, filling in the database credentials and site parameters.A web application for creating simple single-question polls and voting on them, modeled after the StrawPoll.com platform.
The backend is a REST API built on FastAPI (SQLAlchemy ORM, PostgreSQL, validation through Pydantic), with Redis holding the session state and the rate limit counters. The frontend is a single-page application in React + TypeScript (Vite, Bootstrap). Everything runs through Docker Compose, and the API documentation is generated automatically (Swagger).
Instead of simply issuing tokens, I wrote a separate session management module (fastapi_jwt_redis) that plugs into the FastAPI dependency system:
jti identifier, expiration time and not-before time.A React application with client-side routing and background session refresh (the access token is exchanged before it expires). A single poll has its own address, so it can be shared, and the votes already cast by the logged-in user are fetched with one batched request covering every poll on screen.
An online store selling car parts. We built it in a team of five, working in Scrum together with a group from the management faculty, as part of the "Software and Database Engineering" university course.
The store is built with Django (Python) on a PostgreSQL database, with server-side templates and a Bootstrap interface. The application is prepared for the Polish market, works as a PWA and was deployed to Heroku (gunicorn, whitenoise).
My part of the work was the product catalog and the presentation layer: filtering and sorting of the product list, splitting the assortment into sections and categories together with the navigation bar, pagination, discounted prices with a sale view and a special offers section, and moving the home view queries into a separate service layer. On the interface side I prepared, among other things, the responsive navigation bar, the floating cart and the templates for the product page, product list, login, registration and order summary.
Based on an open-source Django module (the comparison list lives in the session, items are added and removed over AJAX), which I extended with a parameter table built from the JSON field: the attributes of all compared products are merged into one set and laid out row by row, with a dash for missing values. Products can be compared within one category.
A puzzle game modeled on the classic Sokoban: the goal is to push every crate onto its designated target tile. Written in C++17 with the SFML library and no ready-made engine. The game loop, state system, entities, animations and UI controls I implemented from scratch. The in-game interface is in Polish.
The project is built with CMake and targets the Win32 (x86) platform, matching the bundled SFML version.
The header (18 bytes) holds the board dimensions, the player start position and the crate count. It is followed by an array of target tile positions (8 bytes each) and the tile grid stored as one byte per field (no tile / floor / wall / crate).
The floor and wall texture variant is drawn from a seed calculated from the level dimensions. This way the board looks varied, yet renders identically on every load.
A console client-server chat for Windows, written in C++ on Winsock sockets (TCP), with no external libraries. The server and the client are two separate command-line applications. All the logic (accounts, ranks, permissions, bans) sits on the server side, and the client only displays output and forwards whatever the user types.
One of my early hobby projects. I wrote it to learn network programming and multithreading.
srand seeded with successive characters of the key and mixed into the data with XOR.GUEST (unregistered), USER, VIP (colors in messages), MOD and ADMIN, compared numerically. A command requires a rank no lower than its threshold.7d, 12h, 30m) and the expiry is stored as a timestamp. Once it passes the entry stops applying, and the remaining time is shown in a readable form.A plain console doesn't work for a chat, because text arriving from the network breaks up the line the user is currently typing. For this project I wrote a separate component that solves that problem:
{number} markers embedded in the content. The same string can be printed with colors or stripped of the markers, which is used for the messages of VIP-ranked users, among other things.A Flappy Bird clone written in Python with the Pygame library. Pygame only handles the window, drawing and input events, while the game layer (objects, scenes, resources, update loop) I built from scratch.
z_index, which sets the layer order.tap (start screen), playing, died and died_new_best, so changing the game state comes down to enabling one scene and disabling the others, instead of hiding individual elements by hand.Falling speed builds up to a terminal value, and the acceleration depends on the phase of flight: an ascent is damped more strongly than a free fall, which produces the characteristic jump arc. After a collision the bird switches to a separate falling mode with higher acceleration and a higher terminal speed, stops only at ground level, and the end screen appears after a short delay.
The record is kept in a binary file preceded by a SHA-256 hash computed from the score and a fixed string embedded in the code. On load the hash is recomputed and compared against the stored one. If it doesn't match (someone edited the file by hand) or the file is corrupted, the record is discarded and the count starts over from zero.
A 2D platformer written in C++ with the SDL2 library. SDL2 only handles the window, texture drawing and keyboard input; the rest (game loop, objects, physics, camera and map loading) I wrote from scratch.
Collisions don't work by pushing an object back once an overlap is detected. For each axis separately, the objects lying in the path of movement are checked and the nearest blocking edge in the direction of travel is found; the new position is clamped to it. This way an object can't skip through an obstacle even at very high speed, and the map borders stop movement on their own.
Gravity builds up with the object's mass until it reaches a set terminal velocity. Touching the ground or the ceiling zeroes the vertical speed and updates the "in air" flag, which controls jumping (you can only jump while standing on the ground).
Horizontal movement accelerates from a starting speed to a maximum one. In the air the acceleration is lower than on the ground and the top speed a bit higher, so running and steering mid-jump feel clearly different. Changing direction in flight slightly adjusts the vertical speed, and a separate key takes the player back to the spawn point.
A roulette simulator inspired by the CSGODouble platform, running entirely in the browser: no backend, built on plain JavaScript with jQuery and Bootstrap. An early project from 2017, from the time I was learning the basics of JavaScript and web development.
The wheel has 15 fields, and a bet is placed on one of three colors:
The algorithm reproduces the "provably fair" scheme used by platforms of this kind: the outcome is fixed before the spin begins and can be verified afterwards. The winning number is calculated from three values:
seed – a secret string disclosed the following day, so the previous day's results can be checked (generated as the hash of a random 48–64 character string),public – a public value, which here is the current date in year-month-day form,round – the round number within that day.The values are joined into a single string and passed through the SHA-256 hash function. The first eight characters of the result are read as a hexadecimal number, and its remainder modulo 15 picks the winning field. Further characters of the same hash also produce the offset within the field, so the pointer stops at a different spot of the same field every time, in an equally verifiable way.
The fields sit on a looped strip in alternating order (red and black on both sides of the zero), and a spin comes down to shifting the background by a calculated distance. The movement slows down exponentially: each step covers a fraction of the remaining distance, so the closer the wheel gets to its target, the more gently it slows. The starting distance is a few full revolutions plus the path to the drawn field, and the rate of deceleration is adjustable with a speed slider.
A separate panel lets you check the generator yourself: manually set or regenerate the seed, public and round values, disable the automatic round increment, change the countdown length and the animation speed, lift the free coins limit, and start a spin immediately without waiting for the countdown to finish. By entering the same three values, any earlier spin can be reproduced to confirm the result wasn't changed along the way.