Projects

Some of my projects.

My work along the way, from Seoul to Pittsburgh.

↳ Click a point to open that project — labels stay hidden until then, so nothing overlaps.

research · biology-led applied · biology-led research · materials-led applied · materials-led Dosimetry Modeling Cardiovascular Modeling Antibacterial Drones Natural Antimicrobial Study
Also a project

This website

You're looking at it — this site is itself a project for this class, not just a place to list the others. Plain HTML, CSS, and JavaScript, no framework, built and coded with Claude (Anthropic) as an AI pair-programmer, then deployed on GitHub Pages.

HTML/CSS/JSno framework
GitHub Pageshosting
ClaudeAI pair-programmer
View the code ↗
Also a project · Python + live API

Strikeout Lab

Strikeout Lab home page with the mission statement, live stats, and an interactive matchup builder
The home page: live league numbers, a mission statement, and a "Try it" matchup builder that draws a forecast on the spot.
Strikeout Lab's Today's Games page ranking which pitchers the opposing bats could help or hurt
Today's Games: every probable starter modeled against the opposing lineup, with the batters behind each number.
Strikeout Lab's Forecast Lab showing a strikeout probability chart
The Forecast Lab: expected strikeouts, the chance of going over or under a line, and how the workload changes it.

swipe for more →

An interactive Python web app that models MLB pitcher strikeouts. It pulls live team, pitcher, batter, and schedule data from the free MLB Stats API, then uses a transparent binomial model to estimate how many strikeouts to expect for a chosen pitcher, opponent, and workload, and how likely the pitcher is to go over a hypothetical line. A daily view shows which pitchers the opposing lineup could help or hurt. Made for CMU 15-113's API assignment as an educational statistics project, with the assumptions and limits spelled out in the app; it is not a betting tool. It runs locally with one command, so this page links to the code and screenshots.

MLB Stats APIfree, no key
Streamlitscipy · Plotly
162 testsplus offline demo mode
View the code ↗    Read the README ↗
Also a project · Flask backend + live APIs

PaperTrail

PaperTrail's paper lookup and result card, showing a GenBank paper's title, authors, journal, citation count, Relative Citation Ratio, and abstract
Drop in a PMID, PubMed URL, or DOI and get the real title, authors, abstract, and iCite citation stats back.
PaperTrail's What Happened Next section with an AI summary of how later papers cited the original one
"What happened next": an AI summary of how later work engaged with the paper, grounded only in the retrieved titles/abstracts of the papers that actually cited it.
PaperTrail's field trend chart showing yearly PubMed publication counts for GenBank-related research
A field-trend chart: yearly PubMed publication counts for an LLM-generated (and user-editable) search query on the paper's topic.

swipe for more →

A research-paper reading companion: drop in a PubMed ID, PubMed URL, or DOI and it pulls the real metadata, abstract, and citation stats from PubMed and iCite, then uses an LLM to explain the paper at three reading levels, summarize how later papers built on or challenged it (grounded only in retrieved titles/abstracts, never invented), and chart how the field's publication volume has trended over the last 20 years. Built for CMU 15-113's backend-on-Render assignment: a Flask API deployed on Render talking to a plain HTML/CSS/JS frontend on GitHub Pages, with every secret read from environment variables and nothing committed to either repo.

PubMed + iCitelive data, no key
OpenAI APIgrounded explanations
Render + Pageslive deploy, both repos public
Try it live ↗    View the backend code ↗    View the frontend code ↗
Also a project · Computer vision + installable web app

Eye Strain Monitor

Eye Strain Monitor's intro screen: a large animated eye logo above the word Begin
The intro: the eye draws itself in, follows your cursor, and blinks. Click it to zoom into the pupil and enter the app.
Three states of the floating widget: normal with a green tint, low blink rate with a muted red tint, and a nudge message with a warmer orange tint
The floating widget stays on top of other apps and mirrors your eyes live. When your blink rate stays low it shows a gentle nudge (shown here with simulated readings).
Eye Strain Monitor's History page with a trend chart of blinks per minute across sessions
History: blinks per minute across sessions with a 5-session average, to see whether your habits are improving (sample data shown).

swipe for more →

A webcam-based monitor for digital eye strain that runs entirely in the browser: no video ever leaves the device. MediaPipe's face landmark model tracks the eyes, and the app turns that into blink rate, full vs. incomplete blinks, gaze, and an estimate of screen distance from the size of the iris. Detection runs in a Web Worker fed directly by the camera, so it keeps working when the window is hidden or minimized (measured at ~20 fps hidden, against 0 fps for the main-thread version). A floating always-on-top widget mirrors your eyes and nudges you to blink or lean back, sessions end with a summary, and a history page charts the trend. Installable as an app. Built for CMU 15-113's Creative Web App project; desktop-first, since it needs a webcam.

MediaPipeon-device face tracking
Web Workerkeeps running when hidden
PWA + Pagesinstallable, live deploy
Try it live ↗    View the code ↗    Read the README ↗
Also a project · Python + vector database

DiagKnows

DiagKnows in a terminal: the query 'breakouts all over my forehead and chin, whiteheads everywhere' returns Acne as a strong match with Dermatologist as the doctor to see
Search by meaning: "breakouts… whiteheads everywhere" finds Acne, matching patient descriptions that mostly use different words, like "pimples" and "blackheads".
DiagKnows adding a new Gout case, then finding it as the top result for a differently worded search
Add a case while the app is running, and it's searchable immediately: a differently worded description finds it first.
DiagKnows answering an off-topic query with No confident match, and a sudden vision loss description with a Seek Emergency Care warning
It won't guess: off-topic text gets "No confident match", and red-flag symptoms get an emergency warning instead of a ranking.

swipe for more →

A command-line symptom explorer built on a vector database. You describe how you feel in plain English, and it searches 1,200 real patient symptom descriptions (the Symptom2Disease dataset) by meaning rather than keywords. It then ranks the conditions your description most resembles, weighting each nearby case by how close it is, and suggests which kind of doctor to see. Distance cutoffs picked from real query data let it say "no confident match" instead of guessing, and a separate collection of red-flag symptoms routes emergencies to a seek-care warning. Users can add their own cases at runtime, everything persists between runs, and an optional OpenAI step explains the matches using only the retrieved text. Built for CMU 15-114's vector database assignment as an educational tool, not a diagnosis. It runs locally in the terminal, so this page links to a demo video, the code, and screenshots.

ChromaDBpersistent, local
1,200 cases24 conditions + user-added
MiniLMlocal embeddings, no key
Watch the demo ↗    View the code ↗    Read the README ↗