The Thread
Solo build · Design & Engineering
A Marvel watch-order site built as a dependency resolver. Name one title and the site computes the shortest honest watch path across eight universes and 216 films and series. 699 characters, 1,893 static pages, English and Arabic. Independent fan project, not affiliated with Marvel or Disney.


- Titles
- 216Titles
- Characters
- 699Characters
- Static pages
- 1,893Static pages
- Unit tests
- 321Unit tests
- Runtime API calls
- 0Runtime API calls
- Commits
- 240Commits
01 / 07
Two doors
Watch-order lists already exist. Each one makes a newcomer and a returning viewer share a single page, and the page serves neither. The Thread gives each their own door. The newcomer gets the Infinity Saga as a spine, 23 films in about 50 hours, Iron Man through Far From Home. The returning viewer types a title and gets the path. The whole product follows from refusing to make those two people share a screen.
- Films in the spine
- 23
- Spine runtime, about
- 50h
02 / 07
Order is derived, never written
Every title is a node and every prerequisite is an edge. Release order, the essentials spine, each universe's story order and the path to any title all fall out of one graph. There is no hand-maintained list anywhere in the repository. Three kinds of ordering data stay separate because they mean different things: a hard dependency, a soft recommendation, and a curated reading order inside one universe, which is not a dependency and must never be stored as one.
The corpus is TypeScript validated by zod, and the build fails on a dozen cross-node rules. A dependency cycle is reported as a path, not a boolean. An essential title depending on a non-essential one fails. A cross-universe detour with no editor's note fails. A missing runtime fails loudly instead of shipping as a confident wrong number.
- Titles in the graph
- 216
- Universes
- 8
03 / 07
Appearances are a join, not a list
A character is in a title when the cast credits for the title name them. Nothing is typed twice, because the second copy of a fact rots. The matcher works on aliases and handles how credits are written in practice, such as Logan / Wolverine or Ted (Man-Thing). Whole segments are compared, never substrings. An earlier substring match put Vision in every title crediting the word Television. Two escape hatches exist, one for real uncredited appearances and one for a credit using the character's word for somebody else, and the second throws at build time the moment the exception stops being needed.
- Characters
- 699
- Episodes
- 2,193
04 / 07
A ranking with no rank column
All 699 characters sort by strength, and there is no powerRank field. The order is derived from species, mutant class, affiliation and each character's own power bullets, scored by a small vocabulary engine, with a hand-ordered head per tier where sources agree. Inserting a character never renumbers anyone. The lesson written into the code, more than once, is this: a bad rank is almost always a thin record or a word the scorer misreads, not a ranking bug. The tier documents are generated from the same definition, so they cannot disagree with the site.
05 / 07
Images at zero cost
216 posters plus 699 portraits plus galleries used up Vercel's free image-optimisation quota. Past the quota the optimiser errors instead of degrading, so the deployed site lost most of its images while localhost looked perfect. The fix took Vercel out of the image path entirely. TMDB serves posters at a width written into the URL. One host of eighteen refuses hotlinking and goes through a free proxy. Everything else is used directly. A full crawl now makes zero billed requests.
- Billed image requests
- 0
06 / 07
Arabic done properly
Full RTL layout with a self-hosted Arabic display face and body face. Western numerals by decision, because those are what GCC streaming and banking interfaces use. One test guards a fact most codebases learn the hard way: JavaScript's \b and \w are ASCII-only and fail open on Arabic text, which silently broke a season-label regex. Approximation is written with the Arabic word, not a tilde, because the tilde is bidi-neutral and lands on the wrong side of a Latin numeral inside an RTL paragraph.
07 / 07
Tests named after the bug they caught
The suite is documented by failure, not by coverage. A render test caught 130 pages rendering empty behind a green build. An end-to-end test caught the CSP blocking every script. A contrast test disproved the design brief's own claim about the brand red on dark: 4.04 to 1, not 4.5. A screenshot matrix of widths, themes and routes caught dark mode unrendered for four commits, and an Arabic runtime reading as 44 hours instead of 1h 44m.
- Unit tests
- 321
- Browser tests
- 55