Adam Burich Open to work

Portfolio

Things I've built

Projects across computer vision, market experiments, learning platforms, games, a family recipe archive, and a couple of browser extensions. The highway danger-scoring system is the one I'm proudest of.

Featured

Behavioral danger scoring from overhead highway video

Solo · June–July 2026 · ~25,000 lines of Python across ~125 modules · 257 commits · built in about three weeks

An end-to-end system that watches highway traffic from overhead video — drone footage or research datasets — tracks every vehicle, and scores each driver's behavior in real time on a 0–100 Danger Index. The goal is to surface the drivers genuinely endangering people around them (tailgaters, weavers, aggressive cut-ins) rather than crude proxies like raw speed, and to do it in a way that is validated against human judgment and explainable signal by signal.

The live analyst view: highway footage with every vehicle boxed and colored by its running danger assessment, beside a ranked board of the worst drivers.
The analyst view mid-run on real drone footage — every vehicle boxed and colored by its running assessment, beside the ranked board of the worst drivers among 1,548 tracked, on a feed the system self-calibrated from a cold start in 10 seconds.

01The problem

Traffic analytics today mostly measures crude proxies: spot speed, hard-braking counts, loop-detector volumes. None of those capture what a traffic officer or safety engineer actually means by "that driver is dangerous" — behavior relative to surrounding traffic. Following two car lengths back at 70 mph. Forcing other drivers to brake. Threading across three lanes.

Overhead video can see all of it, with no instrumentation in the cars. The hard parts are turning pixels into clean, physically-calibrated trajectories; turning trajectories into a defensible danger measure; and proving that measure agrees with human judgment rather than just asserting it.

02Detection and tracking

A car in a 4K drone frame can be a few dozen pixels wide, and naive full-frame detection downscales the image and erases exactly the vehicles you need. The detector slices each frame into overlapping tiles at native resolution, runs a YOLOv8 network pretrained on the VisDrone aerial benchmark over each tile, and merges results with class-aware non-maximum suppression plus a full-frame pass for large vehicles straddling tile seams.

Off-the-shelf detectors see a semi as a flexing pair of cab and trailer boxes, which wrecks tracking. I solved it geometrically first, then at the source — fine-tuning a dedicated whole-rig truck detector using the geometric merger's output as training labels.

Tracking is formulated as a min-cost network-flow problem rather than greedy frame-to-frame matching: every detection is a node, edges carry motion and appearance costs, and the solver finds the globally optimal set of vehicle paths. Physical structure lives in the graph itself — vehicles can't appear or vanish mid-road for free. The guiding principle throughout was to lose a track cleanly rather than recover it wrongly; a dropped track costs coverage, but a wrong recovery silently corrupts every safety metric downstream.

03Self-calibration

Scoring needs meters and m/s, but a drone feed arrives as pixels with unknown scale and orientation. The system bootstraps its own geometry from the traffic it observes — scale estimated from lane spacing against standard lane widths (2.3% median error across a 49-clip sweep), traffic direction inferred from the detections themselves. A deliberate scoping call, informed by simulator experiments: don't chase absolute speed accuracy from uncalibrated video, because the metrics that matter — headways, time-to-collision — only need relative geometry to be right.

04The scoring engine

Ten signals built on surrogate safety measures from the traffic-safety literature — time headway, time-to-collision, forcing others to brake, cutting in with insufficient gap, weaving, speed against surrounding flow — each normalized 0–100 and individually explainable, computed over a rolling three-second window.

Three design choices did most of the work. Aggregation is noisy-OR, not a weighted average, because with an average one genuinely dangerous behavior gets diluted by the nine that don't apply. Follower signals are gated on causal context — braking hard because the car ahead braked is defense, not aggression, and this single idea eliminated the largest class of false positives. And the index is a chronic disposition measure, with a separate acute detector for conflict events graded by physical consequence.

Danger Index — thresholds anchored to human judgment, not to an alert budget

0 Watch
50
Critical
80
100
The live dashboard: raw feed and annotated analyst view side by side, a ranked board of tracked drivers, and a replay drill-down of one flagged vehicle.
Live mode on a 15-minute drone clip: raw feed, analyst view with score-colored boxes, the ranked board of 1,737 tracked drivers, and the drill-down replay of one flagged vehicle — rebuilt from retained footage so any driver's episode can be reviewed on demand.

05Proving it, rather than asserting it

The question disciplining everything above: does the score agree with what a reasonable person calls dangerous? Raters watched pairs of vehicle clips and picked the more dangerous driver, blind to the system's scores — a two-alternative forced choice, which measures the ranking the system actually claims to produce without asking anyone to invent a numeric scale.

ResultMeasure
~92%Pooled human–system agreement on held-out research recordings never used during development
88.5%Pooled agreement on real drone footage, through the full pipeline — detection, tracking and self-calibration included, not just the scorer on clean data
81%Of held-out conflict events where the score was already elevated above that driver's own baseline beforehand. With all proximity information ablated, behavioral signals alone still anticipate ~65% — the score isn't merely re-detecting closeness

Negative results were kept. A time-headway rework that failed to improve human concordance was shelved with its analysis written up rather than merged on vibes. One rater's disagreement traced to a different rubric — they were scoring norm violations while the system scores risk creation — and that was documented as early evidence for officer-selectable weight profiles, rather than treated as noise.

06Performance

Every hot path was profiled before being touched, and every optimization landed only after an equivalence check against the implementation it replaced.

ComponentResultVerification
Scoring engine~2–4 ms/frame — real time at 25 fps with ~10× headroomoutput-identical
Track association25.9 → 6.9 ms/framebit-identical
Flow solve23 s → 0.08 s per clip via OR-tools C++ solveridentical optimal cost
Detection stageFP16 + TensorRT + auto-ROI + tile batchingbit-identical
Live assessment board62 → 0.35 ms per update at 30k driversoutput-identical

Two results worth mentioning because they went the other way: GPU acceleration of the scorer was evaluated and rejected — the workload is many small windows, not big tensors, so the win came from prefix sums and algorithmic complexity instead. And warm-starting the flow solver was refuted by profile: the C++ solve was only ~9% of step time, so the assumed bottleneck wasn't the bottleneck.

07What I'd fix next

A pooled 88.5% from seven raters over a two-dozen-pair deck is encouraging evidence, not proof. The gaps I consider real, roughly in the order I'd attack them:

The toolbox GUI: every pipeline stage, visualizer and validation script registered with its parameters and a one-click Run button, with a live log.
Every script registers in a point-and-click toolbox — the rule being that a tool isn't finished until someone who isn't me can launch it. Here mid-launch of the timed live pipeline, with the log showing calibration warm-up, TensorRT engines loading, and throughput ramping to ~28 fps.

Python · NumPy · OpenCV · PyTorch · Ultralytics YOLOv8 (VisDrone-pretrained + custom fine-tune) · TensorRT · Google OR-tools · SciPy · pandas · stdlib HTTP server + vanilla-JS web UIs · highD dataset · BeamNG.drive for simulated development footage
Provisional patent application drafted and prepared for filing — full specification, 20 claims, 10 figures.

Also

Other projects

2026 · Ongoing · Personal investing project

Silly Prices Holdings

Built on the old Buffett and Graham idea that quality companies sometimes trade at silly prices. The plan: keep a pre-vetted watchlist of wonderful businesses, wait for a temporary dislocation — Google has a bad month — buy at a real margin of safety, and hold indefinitely. Nothing is bought to flip.

The tooling is a zero-dependency Python pipeline, standard library only, over free SEC EDGAR fundamentals and Yahoo prices. It verifies the quality gates from primary SEC filings, builds each company's own-history valuation bands, and auto-generates a public board that rates the roughly 50 largest US-listed companies against a rule-based buy target — the 20th percentile of each name's own EV/EBIT history, with separate lenses for financials, cyclicals, and foreign ADRs.

The qualitative half is automated too. When a name enters the buy zone, Claude researches it with web search into a structured verdict — temporary dislocation or permanent decline, with a confidence and named disqualifiers. That runs as a daily cloud routine, and the board just re-renders from the committed cache, so the verdicts are reproducible rather than one-off.

Python (standard library only) · SEC EDGAR XBRL · GitHub Actions · GitHub Pages · Claude

A personal, long-term investing project and my own methodology. Not investment advice.

  1. WatchlistWonderful companies passing hard quality gates (Piotroski F ≥ 7, ROIC > WACC, Altman Z > 2.99), each with a written moat thesis, built in calm markets.
  2. ScreenDaily flag of any name in the silly-price zone: down ≥ 20% and valued in the bottom ~15–20% of its own 10-year history.
  3. DiagnoseTemporary dislocation or permanent decline? Moat intact and damage bounded, or a value trap? Only temporary proceeds.
  4. ValueBuy only at a third or more below a conservative estimate of intrinsic value.
  5. AcquireIn three tranches: initial entry, deeper once stabilized, and a final add once the thesis is confirmed.
  6. HoldSell only on a broken thesis, a broken management integrity, or egregious overvaluation. Never on price alone.
2026 · Ongoing · Paper-traded research

Can reasoning catch a news story's second-order effect before the market does?

When a policy story breaks, the obvious names get repriced almost instantly. The knock-on effects — whose costs quietly go up, whose competitor just got a gift, whose supply chain tightened — seem to take longer for the market to work out. I don't know yet whether that gap is real and catchable or whether I'm imagining it. This is my attempt to find out.

The idea: read a policy headline, reason one step past the obvious, name who might be on the other side of the trade and why they're stuck — forced to act, slow to react, or trading on emotion — then log a prediction with a date and a fixed exit and score it later. One example: a scary chip-supply headline had people selling crypto miners; the thought going the other way was that fewer imported rigs makes the network less competitive, which helps the machines already running. Right or wrong, I have no idea yet. That's what the scoring is for.

The hard part isn't the ideas, it's not fooling myself. It's easy to remember the guesses that worked and quietly forget the rest, so the point isn't to be right — it's to find out whether the judgment is doing anything at all. The reasoning runs on an LLM, and it's built on a whole-market intraday data pipeline (Databento pulls normalized into partitioned Parquet).

Python · Polars · Parquet · Databento · scikit-learn · LLM reasoning

A personal research experiment and paper-trading exercise. Not investment advice, not a service, and no real orders are placed.

  1. Capture the newsPolicy and regulatory headlines, timestamped so there's a record of exactly what I saw and when.
  2. Find the second-order effectThe fast money already owns the obvious trade. The interesting part is one step removed from the headline.
  3. Guess who's mispricing itEach idea has to name who's on the other side and why they'd be stuck. Often I can't, and that's fine.
  4. Write it down, let it play outLogged with a date and a fixed exit, then scored against what happened. Bad calls stay on the record next to the good ones.

Forward-only, never backtested. Rules fixed before the first prediction. Passed-on ideas logged too. No claims until there's enough data — right now there isn't.

2026 · Solo · Full-stack web app

Mood Music

A Spotify companion that reframes your saved library as a story rather than a list. Its Phases view reads your Liked Songs in the order you saved them and detects the eras your taste has moved through — a mellow acoustic stretch, a high-energy run, a moodier recent turn — each rendered as an expandable timeline you can page through track by track.

Its Mood & Activity search lets you ask your own library for a feeling or a moment — "heartbreak," "late-night coding," "rainy Sunday" — and ranks your songs by how well they match. Each track carries a mood score that blends its audio character with the sentiment of its lyrics, placing it on a valence-and-energy map. The result knows not just what you listen to, but how it feels and when it mattered.

TypeScript · Node.js / Express · React / Vite · Spotify Web API (OAuth 2.0) · ReccoBeats · LRCLIB · AI agent routines

  • Resilient to a shifting upstreamMid-build, Spotify deprecated its audio-analysis and genre endpoints for new apps. I re-architected the enrichment layer around alternative sources (ReccoBeats, LRCLIB) with graceful degradation, so the product survived a breaking change without losing its core idea.
  • Offline AI enrichmentThe semantic work — lyric sentiment, interpreting natural-language mood queries — runs as a batch agent routine that commits results to cache files the app reads instantly. No per-request LLM latency or cost; the hand-off is bridged through git.
  • Change-point detection for erasPhases come from binary change-point segmentation over a smoothed audio-feature trajectory (raw per-track signals were too noisy to segment directly), with each era labeled by how it deviates from the listener's own baseline.
  • Privacy by designSigned-cookie multi-user sessions; personal listening data never leaves the machine. Only an anonymized track manifest bridges to the enrichment routine, and lyrics are never stored — only the sentiment derived from them.
2026 · Solo

The Reinhardt Family Recipe Box

My grandmother has a recipe box our family has cooked out of for decades. There's only one of it, so I scanned every card and put the whole thing online for everyone to use.

The site looks like the box: click a divider tab to open that category, or search across all of it. It's one HTML file, a JSON manifest, and two folders of images — no server and no database, so there's nothing to keep running.

A Python script handles the rest. It reads the original scans, makes web and thumbnail copies, and rebuilds the manifest, pulling titles, categories, and multi-page recipes out of the filenames. Adding a recipe means dropping a scan in a folder and running it again. The originals never change.

HTML · CSS 3D transforms · vanilla JavaScript · Python · Pillow

The recipe box rendered in 3D with its lid open, divider tabs labelled by category standing in staggered rows, and an embossed plate reading Reinhardt Family Recipes.
701
Recipes
926
Card scans, 215 recipes spanning more than one card
22
Categories, one divider tab each
1
HTML file — the entire application
0
Servers, databases, or dependencies to keep alive
2026 · Solo

YT Retitler

A browser extension that rewrites clickbait YouTube titles into honest ones, based on what the video actually says. Every video in your feed gets a small button; click it and the title is replaced with a plain description drawn from the video's own transcript — no withheld payoffs, no manufactured urgency. Click again to revert.

The interesting part is the transcript. YouTube now gates caption access behind a proof-of-origin token that browser requests can't produce, so the extension sidesteps it with a small local helper that fetches the transcript on your own machine — keeping the whole flow private instead of routing it through a third party. The transcript goes to an LLM under a structured-output schema that forces a clean, prose-free title, which is written back in place preserving YouTube's styling.

JavaScript (WebExtensions MV3, Firefox & Chrome) · Python helper · Gemini / Claude

Runs entirely on your machine; API keys stored locally and never leave the device except to the chosen model provider.

2022 · Solo

It Ends

A wall-jumping platformer built in Unity. It started as coursework and turned into something rather larger than the assignment called for — the kind of project where the brief stops being the point about a third of the way in.

Unity · C#

2022 · Deepbrook Software

Cerebrum Visual Editor

A Blockly implementation for Cerebrum, Deepbrook's custom language for setting up environments and context in their nurse-training game. It gave students an approachable way to work with the language, and the transpiler ran both directions so existing Cerebrum files became editable workspaces instead of being rewritten by hand.

Node.js · JavaScript · Blockly · GCP

2022–24 · Serious Games Asia

Unity SCORM/xAPI Logger Plugin

A plugin for logging student actions during gameplay to a Moodle LMS. Before it, every SCORM/xAPI request was hard-coded into the Unity project; afterwards a developer could generate a log for any event without touching the transport layer.

C# · .NET Framework · Unity · SCORM · xAPI

2021–22 · Drexel graduation project

DAITrader

An investment scenario simulator that used machine learning to produce possible projections of company performance. I proposed it and managed the development across eight months. It does not produce accurate projections for stock values — but it was a good experiment in whether that particular approach was valid at all, and the answer to that is worth having.

Python · Flask · Docker · scikit-learn

Chrome Web Store

Following Filters for Twitch

A Chrome extension I wrote to fit my own needs: it injects a filter control into Twitch's followed-channels page so you can show only channels playing selected games, or hide them. Shipping it was also how I learned what it takes to get listed in a standardized marketplace.

JavaScript · Chrome Extension APIs