Inspiration
New York publishes a city average that looks manageable. In 2024, PM2.5 across the city was 6.3 µg/m³, under the EPA annual standard of 9.0. About half of renter households pay 30% or more of income. The latest new one-bedroom ask is $3,750. Child asthma, measured in 2017–2019, is 62 per 100,000. Those figures do not rise and fall in the same neighborhoods. One of the 42 neighborhoods sits above the EPA line. Rent burden is a Census share, not a grade of the people who live there. A new-lease ask is not the rent a tenant already in place pays. Breathing Room started from that gap: a single city number can be true and still hide where the burden lands. The tagline is the product. Rent, air, and asthma do not rise together. Find your neighborhood and the next step.
What I learned
A rank is safer than a made-up index. For each neighborhood, 2024 PM2.5, the share of renters paying at least 30% of income, and the change in new one-bedroom asks are each ranked among the 42 neighborhoods. With weights (w_i) and percentile ranks (r_i), the score is [ S = 100 \cdot \frac{\sum_i w_i r_i}{\sum_i w_i} ] If a rent trend has fewer than 20 listings at either end of the window, that term drops out and the other weights rescale. Equal weights are the default. (S) is a weighted average of ranks. It is not a forecast, and it is not a judgment of a neighborhood’s residents. The same restraint applies to the line on the outlook page. Published points are fit with ordinary least squares, [ y = a + bx ] Air is carried one year ahead. A thick rent series is carried one month ahead. A one-period series is not extended. The line is the fit through points the city already published. I also learned to keep measures in their own units. Asking rent and Zillow’s Observed Rent Index answer different questions. Deeply affordable unit counts are financed production, not vacant apartments. Asthma rates stay labeled 2017–2019. NYCCAS annual means end in 2024, the year before congestion pricing began on January 5, 2025, so this record does not show whether the toll changed the air.
How we built it
Breathing Room is a DeepSpace app: TypeScript, React, and a Cloudflare Worker. The map is MapLibre on OpenFreeMap. Geography is the 42 United Hospital Fund neighborhoods used by NYC Health. The snapshot is built from public sources and shipped with the app:
- NYC Department of Health, NYCCAS, for air quality and health impacts
- US EPA Air Quality System monitor summaries
- American Community Survey rent burden, ZIP counts summed into the neighborhood
- FirstMover NYC rental listing extracts, placed by ZIP centroid
- Zillow Observed Rent Index
- NYC Housing Preservation and Development affordable-housing production
- MTA congestion-relief zone vehicle entries, for the toll schedule, not for an air effect
The atlas opens on the city. A place page ranks up to three next steps, such as a rent-history request, an asthma report, or that day’s air reading, and links to the office that actually holds the record. The desk rewrites a few metric sentences; the app appends the official links afterward. Neighborhood forums are for neighbors. The true-cost page takes an address and a monthly rent and writes a dossier from the same snapshot, including a comparison of the 2024 annual mean to the WHO guideline of 5 µg/m³. It does not invent days above that guideline.
Listings are separate from the city extract. Hosting one costs 1 XRP on the XRPL testnet. The browser cannot insert the row. The worker accepts the post only after it reads the ledger and finds a validated Payment to the configured address, for at least the fee, with a hash that has not been used. The wallet secret never touches the server.
Challenges
The hard part was refusal. Block-level rent, hourly pollution, eviction rates, and a dollar health bill were all tempting and all absent from the sources. Putting them on the map would have made a stronger demo and a false one.
Time did not line up. Listings run through August 2026. Air is an annual mean through 2024. Asthma is a three-year rate from 2017–2019. Rent burden is the 2020–2024 ACS, and this page does not carry the Census margins of error. Showing those clocks on one screen without merging them into a single “today” number took more design work than the map did.
Payments had a similar trap. A button that says “pay first” does not stop a signed-in client from creating a listing directly. The check had to move to the worker, and the receiving address had to come from configuration rather than a hardcoded wallet.
The last challenge was tone. An alarming neighborhood poster is easy to remember and easy to misread as a verdict on the people who live there. The page that held up was the quieter one: the city average, the split underneath it, and a next step that goes to a real office.
Built With
- cloudfare
- deepspace
- grok
- hono
- node.js
- photon
- react
- tailwind
- typescript
- vite
- zod
Log in or sign up for Devpost to join the conversation.