Broadcast-style onchain city map for Nansen CLI.
Nansen City turns Nansen signals into a living market city instead of a raw terminal dump. Smart money becomes towers, cross-chain movement becomes transit corridors, wallet behavior becomes neighborhoods, and risk becomes visible urban pressure.
The goal is simple: make Nansen CLI output legible in one frame, useful in motion, and strong enough to share as a GitHub demo and an X submission artifact.
- Market city UI: a large central city map with supporting rails, inspector panels, and a broadcast-style information surface
- Signal districts: Smart Money Tower, Whale District, Bridge Station, Meme Alley, Risk Zone, and Wallet Homes
- Shared data pipeline: app and CLI both consume the same normalized city snapshot path
- 3D scene plus fallback map: WebGL stage for richer city rendering, with a structured fallback surface when full rendering is unavailable
- Standalone artifact output: build a directly openable HTML artifact for local review and sharing
- Signal bundle bridge: live Nansen CLI results are normalized into an intermediate bundle before the city snapshot is rendered
- Generated snapshot loading: the app can now read a generated snapshot file instead of being hard-wired to mock data
A district is a signal family.
- Smart Money Tower: conviction inflows
- Whale District: holder concentration and entity stacking
- Bridge Station: cross-chain movement and route pressure
- Meme Alley: heat, velocity, and overreaction
- Risk Zone: exit pressure and distribution
- Wallet Homes: labeled wallets and readable profiles
A building is a token, wallet cluster, entity, or flow object rendered as urban structure instead of table output.
A route is a capital corridor between districts. Routes are used for bridge activity, reinforcement flow, and risk spillover.
The UI does not read raw API output directly. Everything flows through a normalized CitySnapshot model first.
The final live step is designed around a signal bundle. Real Nansen CLI results will be mapped into this bundle, then transformed into the city snapshot consumed by the app.
app/ is the runtime UI layer.
app/index.html: shell entryapp/main.js: Three.js scene, inspector logic, and app renderingapp/tailwind.css: UI tokens and product styling
src/city/ holds the city model and shared rendering data.
types.ts: canonical city typesmock-snapshot.ts: current mock city datasetruntime-data.ts: snapshot normalization, accent overrides, and scene payload generationrenderers.ts: artifact HTML and SVG rendering for the demo export path
src/nansen/ is the live-data preparation layer.
live-plan.ts: 10+ call live query plan for the hackathon requirementcity-collector.ts: collector interface with mock support and live CLI-backed collectioncity-signal-bundle.ts: bridge format from Nansen results intoCitySnapshotlive-city.ts: orchestration layer that runs discovery, drill-down, and verification queriescli-runner.ts: shell runner for the installed Nansen CLI
src/cli/ provides demo and export commands.
render-city.ts: render city artifacts from mock data or a signal bundle JSON fileplan-live-city.ts: generate the live Nansen call plan markdown
Prerequisites:
- Node.js 20+
- npm
nansen-cliinstalled for live collection- Nansen CLI authentication for
npm run city:live
Install and run:
npm install
npm test
npm run app:build
npm run city:demo
npm run city:live-plan
npm run city:liveUseful local entry points:
- Standalone artifact:
artifacts/nansen-city-standalone.html - App dev server:
npm run app:serve - Preview server:
npm run app:preview
The repo now includes vercel.json for static deployment.
- Import the GitHub repo into Vercel
- Keep the default install command
- Let Vercel run
npm run app:build - Deploy the generated
dist/output
app:build also copies the latest artifacts/nansen-city-demo.json snapshot into dist/, so the deployed root page can load the live-generated city state without extra server code.
Generated artifacts:
artifacts/nansen-city-standalone.htmlartifacts/nansen-city-demo.svgartifacts/nansen-city-demo.htmlartifacts/nansen-city-demo.jsonartifacts/nansen-city-live-bundle.jsonafter a live runartifacts/nansen-city-live-plan.md
Recommended demo sequence:
- Open the city map first and let the stage carry the story.
- Show district switching between Smart Money, Bridge, Meme, Risk, and Wallet views.
- Click structures to reveal why a building exists and what signal supports it.
- Show that the same city can be rendered from the CLI into HTML, SVG, and JSON artifacts.
- Point out that the app can switch from mock to generated snapshot data without a UI rewrite.
The strongest framing is:
Nansen City is a market broadcast surface generated from Nansen signals.
The project is deliberately split into three layers:
- Raw Nansen CLI results
- Signal bundle
- City snapshot and scene payload
This keeps the final live integration narrow. When API usage begins, the work is only:
- collect real Nansen outputs
- map them into the signal bundle
- render the city from the resulting snapshot
No UI rewrite should be needed at that point.
app/
index.html
main.js
tailwind.css
src/
city/
mock-snapshot.ts
renderers.ts
runtime-data.ts
types.ts
cli/
plan-live-city.ts
render-city.ts
nansen/
cli-runner.ts
city-collector.ts
city-signal-bundle.ts
live-city.ts
live-plan.ts
artifacts/
nansen-city-standalone.html
nansen-city-demo.html
nansen-city-demo.svg
nansen-city-demo.json
nansen-city-live-plan.md
docs/
PLAN.md
DEVELOPMENT_METHOD.md
STATUS.md
plan.md
Run these before pushing:
npm test
npm run app:build
npm run city:demo
npm run city:live-planUseful checks:
- confirm the standalone artifact opens cleanly
- confirm
city:demoregenerates HTML, SVG, and JSON - confirm
city:livefails cleanly with an auth error when no key is configured - confirm
city:livewrites both snapshot and live bundle files once authenticated - confirm the signal bundle path can render the city without touching the API
The project is now beyond UI-only prototyping.
- product UI and city rendering are in place
- app and CLI share the same data pipeline
- mock snapshot rendering is stable
- signal bundle mapping exists
- live collector orchestration exists and is ready once CLI auth is present
- app runtime can load generated snapshots instead of only the built-in mock
The remaining blocker is no longer frontend structure or data plumbing. It is only live Nansen authentication and the first authenticated run.
- render a true live city snapshot
- capture final screenshots and demo video
- post the submission to X with GitHub proof and Nansen call coverage
