ETOgaosion/DreamPrice

Detailed Price of My Dream

★ 0Forks 0JavaScriptGitHub ↗Compare

README

DreamPrice

Deploy

dreamprice — what the dream actually costs →

Seven assets across three countries, costed line by line from primary sources, and priced per year, per month, and per day.

Asset Where
🇨🇳 Lotus Emeya 600 SE (owned) Shenzhen
🇨🇳 Ferrari Amalfi (new) Shenzhen
🇨🇳 Duplex loft (rented) Shenzhen
🇯🇵 Nissan GT-R R35 (used) Tokyo
🇯🇵 Tower mansion (rented) Tokyo
🇳🇴 Mercedes-AMG (used) Tromsø
🇳🇴 Small house (rented) Tromsø / Lofoten

What it does

Two pages, deliberately.

The front page answers the question and nothing else — four tables, one per period: per year (每年), per quarter (每季度), per month (每月), per day (每天). Each lists the seven assets dearest first, with a tint behind each row showing its share, and a total. The one-off cost sits separately below, because it is not a period and folding it into the tables would make them lie.

There are exactly two buckets, and depreciation is in neither. You buy a car once, and after that it costs servicing, repairs, insurance, fuel, tax, tyres and parking to keep. A car being worth less later is a change in what you own, not a bill that arrives — so the purchase is never amortised across the years, and the per-year figure is one year of running cost rather than an average. Moving the horizon slider does not change it. Resale value still appears on the detail page, clearly marked as context.

The detail page is where you configure and interrogate. Pick a trim, a model year, a district and a mileage. Every one of the 93 line items carries a DATA ↗ link straight to its source, and hovering the row opens a card with the evidence: the figure, its low/base/high band across the three scenarios, the arithmetic that produced it, the raw sourced numbers it was built from, and whether it is taken directly from a source or derived. The page also carries the composition chart, the caveats and the source list.

Settings live in localStorage, so anything you change on one page is already applied on the other. Three scenarios (optimistic / realistic / pessimistic) drive every range at once, and a horizon slider projects the year-by-year running cost as inflation and rent escalation bite.

The Emeya is already bought and the Ferrari is a new order. The GT-R and the AMG are budgeted second-hand at roughly ¥500,000 CNY each — about ¥11.4M in Tokyo and NOK 695,000 in Tromsø.

Data

Research date 2026-09-15. Sourcing is primary or official wherever one exists: Chinese State Council and MOF tax notices, Japanese prefectural tax tables and Nissan's own R35-specific service price list, Norwegian Lovdata statutes and Skatteetaten rate tables, SSB and 総務省 statistics, manufacturer price lists, and live listings from Guazi, goo-net, FINN and 贝壳. Where only listings or trade estimates exist, the line is tagged estimate in the UI. All 190-plus sources are linked at the bottom of the page.

A few findings worth knowing before you read the numbers:

  • The NEV purchase-tax holiday ended, and options are inside the tax base. From 2026 the relief is half the 10% rate but capped at ¥15,000 per car, so the cap binds above roughly ¥339,000 on the invoice — and past that point every extra yuan of options is taxed at the full 10%, not 5%. On the ¥638,000 Emeya invoice the ¥50,000 of options cost ¥4,425 in tax on their own, and the whole car pays ¥41,460 versus ¥28,230 had it been invoiced in 2025.
  • 環境性能割 was abolished on 2026-03-31. Any Japanese cost guide written before this year is wrong.
  • You cannot insure an early R35 for what you pay for it. Real 2026 quotes on a 2008 car returned an agreed value of ¥4.35–4.90M against a ¥9–10M purchase price, and hull cover disappears entirely at 20 years from registration.
  • Buying used in Norway skips engangsavgift entirely. It is paid once at first registration and never re-levied, so a NOK 700,000 budget reaches cars that cost NOK 1.5M new. Your whole tax bill is 1,942–4,532 kr.
  • A Ferrari cannot be registered in Shenzhen by someone who already owns a car there. 《小汽车增量 调控管理实施细则》第十五条(三) restricts the petrol-capable plate to applicants with no Shenzhen-registered car, 第十六条 offers a second quota for BEVs only, and selling the Emeya yields a BEV-type renewal quota. The plate is a gate, not a line item.
  • SSB does not publish Tromsø rent. Live FINN listings for an actual house are 22,000–36,000 kr, not the 13,000 kr that gets quoted second-hand.

Running it

Static site, no build step, no dependencies.

python3 -m http.server 8000   # then open http://localhost:8000
node scripts/check.mjs        # validate the model and data

Layout

index.html              overview — the four period tables
details.html            configuration, line items, caveats, sources
assets/css/styles.css
assets/js/data.js       researched figures, sources and caveats
assets/js/model.js      cost engine, FX, periods, year-by-year schedule
assets/js/state.js      shared settings, persisted across both pages
assets/js/overview.js   renders the period tables
assets/js/details.js    renders the asset cards and chart
scripts/check.mjs       pre-deploy validation
.github/workflows/deploy.yml

CI

Every push to main runs three jobs; a pull request runs only the first.

Validate walks every asset against every variant, scenario, per-asset input extreme and horizon — about 370,000 assertions in under two seconds. It checks that each line item is finite and non-negative, carries a known category, links to a source that exists in the registry, and ships at least two underlying data points for the hover card; that each asset's inputs default to legal values; that the per-year figure equals one year of running cost and does not move when the horizon changes; that no depreciation line ever reaches the annual bucket; that FX conversion round-trips losslessly; that a quarter really is a year divided by four and each period table's rows sum to the total it prints; and that every element each page's script writes into actually exists in that page's markup, with the two pages linking to each other. It also asserts scenario ordering: the optimistic case must cost less than the realistic one, which must cost less than the pessimistic one. That last check exists because it caught a real bug — the R35's appreciation ranges were inverted, which made the pessimistic scenario come out cheapest.

Deploy publishes to GitHub Pages via actions/deploy-pages, uploading only index.html, details.html, assets/ and .nojekyll.

Verify then fetches the live URLs and confirms both pages and every asset file return 200 and the markup still contains its entry points — because deploying successfully and rendering correctly are different things.

To change an assumption, edit data.js — it is deliberately the only file with numbers in it. Ranges are {low, base, high} where low is the optimistic case.

Caveat

Not financial advice, not a quote, and not a substitute for calling an insurer. Four lines in particular need real quotes before you act on them: Emeya insurance, GT-R tyre life, and AMG insurance and servicing.

Contributors

ETOgaosion

Issues