🌆 What is CityPulse?

CityPulse is a real-time smart city intelligence dashboard that gives residents, planners, and anyone who lives in a city a unified, live view of what's happening around them — air quality, traffic, noise, energy, transit, community safety, and neighborhood health — all in one place, across seven major US cities.


💡 What Inspired Me

I kept noticing the same problem: cities generate enormous amounts of data, but none of it is accessible to the people who actually live there. If you want to know whether the air is safe to breathe, you open one app. Traffic, another. Transit delays, another. Safety incidents, a government website buried behind three clicks. None of these tools talk to each other, and none of them tell you what to do with the information.

I wanted to build something that answered a simple question: what is actually happening in my city right now? And I wanted it to be beautiful, fast, and smart enough to give you real recommendations — not just raw numbers.


🛠️ How I Built It

CityPulse is a fully standalone single-page application — no build step, no backend framework, just one index.html deployed on Vercel with a lightweight serverless API route for AI.

Architecture decisions I'm proud of:

  • Zero build tooling. React 18, Recharts, and Leaflet are all loaded via CDN. Babel Standalone transforms JSX at runtime. This keeps the project portable and instantly deployable anywhere.

  • Multi-city data architecture. Every city (SF, NYC, Chicago, LA, Seattle, Miami, Austin) carries its own neighborhoods, profiles, transit routes, alerts, community reports, and sustainability data. A module-level profile cache (_profileCache) updates on city switch so every component stays in sync without prop-drilling.

  • Live sensor simulation. A jitter() function applies realistic variance to neighborhood profiles every 12 seconds, simulating live sensor feeds. The dashboard health scores, AQI readings, and traffic values update in real time.

  • AI integration. The AI Neighborhood Briefing and Eco Tip features use Groq's llama-3.3-70b-versatile model via a Vercel serverless proxy (/api/chat.js). The API key is stored server-side in environment variables — never exposed in client code.

  • Interactive live map. Leaflet.js renders neighborhood markers with color-coded overlays for seven data layers. Switching cities triggers a smooth flyTo animation that repositions the map to the new city center.


🧗 Challenges I Faced

React Rules of Hooks. My biggest bug was a useEffect placed after a conditional early return inside the App component. When users picked a city, React detected a different hook count between renders and crashed — producing a blank screen. Tracking down a hooks violation in a single compiled HTML file with no dev tools was genuinely painful, but also a great lesson.

Multi-city state consistency. Getting every component to re-render correctly when the active city changes required careful design. I used a mutable module-level cache that resets on city switch, so getProfile() always returns the right neighborhood data for whichever city is active — without touching every component's props.

CDN load ordering. Leaflet CSS must load before React, Recharts before Babel, and Babel last. Getting this order wrong produces silent failures that are very hard to debug without a build system's dependency graph.

AI latency UX. The AI briefing cards needed to feel useful even before the Groq response arrives. I added graceful loading states and fallback messages so the UI never feels broken — regardless of whether an API key is configured.


📚 What I Learned

  • How to architect a genuinely complex React application with zero build tooling
  • How Leaflet's imperative map API integrates cleanly with React's declarative model
  • How to design a serverless AI proxy that keeps API keys secure on Vercel
  • That the React Rules of Hooks exist for very good reasons
  • How much polish matters — a dashboard that looks trustworthy makes the data feel more credible

Built With

Share this project:

Updates