DynoCar Spec Compare
What it does for you
Side-by-side car spec comparison with direction-aware best values, deltas, derived metrics, and hand-built SVG radar and bar charts.

Screenshots

In more detail
Dyno puts two to four cars side by side and does the math a spec sheet leaves out: who wins each row, by how much, and what the numbers imply. It ships with a garage of 26 cars, from a Ferrari F12 Berlinetta to a Mazda MX-5, and you can add your own. It adds the figures enthusiasts argue about, like power to weight and price per horsepower.
Honest limits
Figures are manufacturer or widely published numbers for the stated model year, not verified tests, and nothing records where each one came from. The quarter mile is a formula estimate. A shared link only carries built-in cars, so a custom car does not travel with it. Checked by tests and screenshots, not by a room of car people.
How I built it
One of the parallel Claude Code builders from the September 19 one-shot night, and one that shipped the same night. I directed the car list, the fields, the derived metrics, the rule that "better" has a direction per row, and the rule that the quarter mile is labeled an estimate everywhere it appears. Claude Code wrote specs.js, the dataset, and 144 assertions first, then the UI. It drew the radar and bar charts by hand in SVG from core functions instead of pulling in a chart library. Logged time was about 0.4 hours.
The screenshots did real QA here. The first one showed garage rows stretched to 110 pixels. The second showed model years printed as "2,021" with a delta next to them, and seats being crowned the best value. All of it got fixed before finishing, with two new assertions.
What I learned
- A comparison table needs direction as data, not special cases. One
betterflag (high, low, or none) on each row drives the highlight, the delta color, and the radar inversion. - Lower-is-better radar axes should use min divided by value. The best car sits at 1.0 and the rest scale proportionally. Plain min-max pins the worst car to zero and makes small gaps look huge.
- Unit toggles apply to deltas and derived units too. Convert a delta after subtracting, and "price per hp" becomes "dollars per kW" by dividing by the factor, not multiplying.
- Generic class names bite in a single-file app.
.emptyfor the empty state also matched.swatch.emptyand inflated every garage row. - Years are numbers that must not be formatted like numbers.
What carried forward
The DOM-free core that the page and verify.mjs share is the pattern from #9 through #11, and it ran on the standard serve.mjs. The design-lint hook earned its keep too: it flagged a width transition on the bars, which became a transform instead. The "direction as data" idea is a cousin of the single-registry approach in #25, built the same night. Headless Chrome also hung past the shell timeout once, though the files were written, which was a reminder to check the output files rather than trust the exit.
If I took it further
I would store a source and test condition with each figure (manufacturer claim versus magazine test) and let custom cars travel inside the share link.
#027 Built with Claude Code September 19, 2026 144 automated checks