Paralympic Boccia AI Scoring
In Paralympic Boccia, referees measure ball distances by hand and matches stall. Cameras and the cloud now do it live, to 2 mm, and matches run 57% shorter.
▍

I build AI systems that people actually use, from computer vision to agents.
Currently building an agentic AI platform for the fitness industry at NexScale. Previously: an M.Sc. in AI at the University of Windsor, and a Paralympic Boccia scoring system with AWS, featured on Bahrain International TV.
I'm Nawaf, welcome to my corner of the internet! I'm a Software, ML & AI Engineer working across machine learning, computer vision and deep learning, currently working on agentic AI at NexScale, an AI Business Partner for wellness and fitness businesses.
I completed my M.Sc. in Computer Science (Specialization in Artificial Intelligence) at the University of Windsor, where my thesis was on change detection for indoor mobile robots using stereo vision. Before that, I completed my B.Sc. (Honours) in Computer Science at the University of Bahrain, and topped Computer Science nationally in Bahrain's 2019 Grade 12 CBSE exams.
Scroll on to see what I've built, or ask Nano, my on-site assistant, anything about my work.
In Paralympic Boccia, referees measure ball distances by hand and matches stall. Cameras and the cloud now do it live, to 2 mm, and matches run 57% shorter.
My M.Sc. thesis: a system that lets an indoor robot detect what has changed since its last visit, by first making sure it only compares views of the same place.
A personal AI assistant that runs on my own server around the clock, works through Telegram and Signal, and sends each message to the cheapest AI model that can handle it.
Hospital analytics for an AI research centre: validated data pipelines, a live KPI dashboard, and a forecast of bed occupancy.
A fantasy Formula 1 league for six friends: pick drivers, lock picks before each race, and the standings update automatically from live race data.
Predicts the winners of professional Valorant esports matches before they are played. Over 42 matches it called 33 correctly, against 29 for the betting odds.
In Paralympic Boccia, referees measure ball distances by hand and matches stall. Cameras and the cloud now do it live, to 2 mm, and matches run 57% shorter.
My M.Sc. thesis: a system that lets an indoor robot detect what has changed since its last visit, by first making sure it only compares views of the same place.
A personal AI assistant that runs on my own server around the clock, works through Telegram and Signal, and sends each message to the cheapest AI model that can handle it.
Hospital analytics for an AI research centre: validated data pipelines, a live KPI dashboard, and a forecast of bed occupancy.
A fantasy Formula 1 league for six friends: pick drivers, lock picks before each race, and the standings update automatically from live race data.
Predicts the winners of professional Valorant esports matches before they are played. Over 42 matches it called 33 correctly, against 29 for the betting odds.
In Paralympic Boccia, referees measure ball distances by hand and matches stall. Cameras and the cloud now do it live, to 2 mm, and matches run 57% shorter.
In Boccia, players throw balls as close as they can to a target ball. Officials measured every distance by hand, which stopped play and lengthened matches.
In short: cameras measure the balls automatically, and the score updates live on every screen. A computer-vision measurement pipeline works from mounted-camera footage and feeds an event-driven AWS backend, IoT Core → Lambda → DynamoDB → API Gateway WebSocket API, that streams scoring events and keeps every client in sync in near real time. Scoring state is modelled in DynamoDB, which supports replay, auditing and UI sync. A Unity 3D replay visualises the tracked ball trajectories, with replays and metadata stored in Amazon S3 for replay on demand.
I led the five-person team from problem definition with the Bahrain Paralympic Committee and AWS mentors through to live demos: task allocation, integration milestones and stakeholder demos. I also owned the Unity 3D replay subsystem, which the clients requested and the team had judged infeasible within the four-month timeline. I learned Unity for it and delivered it ahead of schedule.
Matches got 57% shorter, with 2 mm precision in live trials. The project took first prize from AWS and the Best Technology Project Award from the Bahrain Parliament and National Assembly, was featured on national TV and the AWS blog, and drew visits from Boccia International Sports Federation (BISFed) leadership.
My M.Sc. thesis: a system that lets an indoor robot detect what has changed since its last visit, by first making sure it only compares views of the same place.
A robot that moves through the same indoor space repeatedly needs to detect what is new. Comparing frames that show different spots produces false detections.
In short: first find the matching earlier view, then compare the two in 3D. The thesis, "A Hybrid Stereo-Aware Change Detection System Using 3D Feature Clustering and Plane Residuals", pairs stereo depth estimation (SGBM disparity) with sparse keypoint matching (SIFT with FLANN) to align the views, fits the ground plane with RANSAC, and flags changes from 3D feature clusters and plane residuals. In front of it sits an embedding retrieval gate, PyTorch ResNet-18 embeddings with similarity search, top-5 candidates and a threshold, so the detector only compares plausible pairs. It also includes chessboard-free stereo calibration, dataset tooling and an evaluation harness.
The pipeline end to end, including collecting the footage (about 15k frames per camera) and hand-auditing part of the dataset.
70.83% precision and 75.55% recall: about 7 in 10 flagged changes were real, and it found about 3 in 4 of the real changes, measured against hand-audited ground truth on a subset of the ~30k self-collected stereo frames.
A personal AI assistant that runs on my own server around the clock, works through Telegram and Signal, and sends each message to the cheapest AI model that can handle it.
Sending every request to a top-tier model is costly when many tasks can be handled by a smaller one.
In short: easy messages go to small, cheap models, and only hard ones reach the expensive ones. Hermes runs in Docker on an Oracle Cloud ARM instance, managed with Coolify, and is reached through Telegram and Signal. A router sends each task through OpenRouter to the cheapest model tier likely to handle it, and escalates only when needed. Skills plug in on top, so a new capability is a small module rather than a rewrite.
An always-on assistant that runs on a small monthly budget.
Hospital analytics for an AI research centre: validated data pipelines, a live KPI dashboard, and a forecast of bed occupancy.
Hospital demos kept being reworked because the underlying data changed shape without warning.
In short: clean the data automatically, check it before anyone sees it, then chart it and forecast it. Python pipelines (pandas, scikit-learn) turn raw hospital data into KPI-ready datasets, with automated data-quality checks for schema and consistency, missingness and outliers that stop the pipeline when they fail. A Django REST API feeds a React dashboard of interactive KPIs, and a bed-occupancy forecast is benchmarked against time-series baselines with time-based validation. Evaluation lives in repeatable notebooks, and the assumptions, method and results are documented in technical reports, including the data standardisation the forecast needs to stay stable.
About 10% average error on bed occupancy under time-based validation, and roughly 30% less demo rework.
Upload a resume, and optionally a job description, to get a FIFA-style player card that rates six strengths, each with a one-line reason.
Keyword-matching resume tools score on keyword overlap, penalise industry switches, and don't explain their scores.
In short: one AI call reads the resume and rates it like a footballer, explaining every number. One endpoint, POST /analyze: PyMuPDF pulls the text, the prompt scales scores by experience (0.8× for 0–2 years up to 1.0× for 10+), a single Gemini Flash call scores six dimensions with a one-line reason each, and a regex parser turns a strict markdown contract into JSON for the React card. The markdown contract replaced Gemini's JSON mode, which drifted between model versions. Role fit is scored separately from domain fit, so an ML engineer from finance can still score well for a healthcare ML role. The service is containerised and deployed, with error handling and guaranteed cleanup of uploaded files.
A live demo on GitHub Pages with the API on Render: about 1–2 seconds per card when warm, at near-zero cost.
A fantasy Formula 1 league for six friends: pick drivers, lock picks before each race, and the standings update automatically from live race data.
In short: when a race ends, the app detects it and updates everyone's points. A serverless, event-driven backend in Python: Azure Functions process live OpenF1 data, Event Grid carries the events, and Cosmos DB holds the league. Picks lock before each race, then results and standings update automatically. Asynchronous events could arrive concurrently, so writes go through idempotency locks in Cosmos DB to keep the data consistent. Built to learn Azure.
A drafting league that ran for a 24-race season with no manual upkeep and consistent data. The system design and live-API debugging are written up as an engineering deep-dive.
Predicts the winners of professional Valorant esports matches before they are played. Over 42 matches it called 33 correctly, against 29 for the betting odds.
In short: learn from each team's season stats, then predict the next match. There's no public API, so Selenium scraped rib.gg for every Americas Kickoff and Stage 1 match: pistol rounds, first kills, KAST%, clutch%, eco and buy-round wins, and XvY conversions. A Random Forest predicts each match from the two teams' season averages, and results are rescraped at the end of every game week before the next predictions. A Dockerised FastAPI service serves the model to a React front end where you drag teams in to get a prediction.
Over 42 matches of the 2025 Valorant Champions Tour it called 33 correctly (78.6%), against 29 (69.0%) for Stake.com's odds on the same games, all predicted before the matches were played.
tracks every player in football footage with their team, speed and distance, drawn like a FIFA broadcast
Raw match footage doesn't show who ran how far, how fast, or which team had the ball.
In short: the model detects players, the referee and the ball, follows each one across the clip, and works out real speeds and distances. Built on Code in a Jiffy's tutorial and extended: a YOLOv5s model fine-tuned on a Roboflow football dataset to tell players, referees and the ball apart (and ignore the crowd), ByteTrack to keep each player's ID across frames, K-Means clustering on shirt colours to assign teams, and a perspective transform with camera-movement estimation to turn pixels into real speed and distance. Tested on 30-second Bundesliga clips.
FIFA-style overlays on the footage: ellipse markers under players, a marker on the ball and the closest player to it, plus each team's possession.
recognises a clothing item's type and occasion, then builds outfits whose colours go together
Recommending an outfit requires knowing what each piece is, when it is worn, and which colours go together.
In short: label clothes by type and occasion, then pair them using colour theory. I hand-annotated photos from the Polyvore dataset with their occasion (party, casual, formal) and type (upper, lower, shoes, over), and trained a Roboflow multi-label classifier on them. Each item's average colour is detected and stored with its labels, and outfits are generated to fit one of three colour schemes: complementary, analogous or harmonic.
Complete outfits matched by occasion, with colours that follow one of the three schemes.
compares three fine-tuned language models at classifying the stance of climate tweets: BERT reached 90%, and an ensemble of all three 93.37%
Choosing which transformer to fine-tune for stance classification on climate tweets.
In short: train three well-known language models on the same task and tweets, compare them, then combine them. A Kaggle dataset of 43,943 climate-change tweets labelled pro, anti, neutral and news, cleaned with NeatText. I fine-tuned BERT, DistilBERT and RoBERTa with the same modular PyTorch and Hugging Face pipeline on a laptop GPU (GTX 1650): 2 epochs, batch size 8 with 2-step gradient accumulation, learning rate 2e-5, weight decay 0.01 and warmup, evaluating every 805 steps. Then I combined all three into an ensemble.
BERT was the best single model at 90% accuracy, ahead of DistilBERT (88%) and RoBERTa (87%). The ensemble of all three reached 93.37%.
re-plans two real Bahrain bus routes using real road travel times: about 24 minutes, or 16.55%, faster on average
Bahrain's public bus routes weren't ordered for the shortest real travel time between stops.
In short: measure the real road travel time between every pair of stops, then reorder the stops. I built datasets from scratch for two real routes, U1 and U2. Instead of straight-line distances, the system uses the Google Maps API for the real road distance and travel time between each pair of stops, picks the optimal stop order, and plots the proposed route on Google Maps.
The proposed routes cut travel time by 16.55% on average, saving about 24 minutes.