# Skyline: City Stats

> Studio hours booked per city as towers, each with its share on a rooftop sign. Switch the year and the towers grow or shrink to it.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/skyline-stats-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/skyline-stats-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/skyline-stats-demo/light.png
- Registry item: https://keyframeui.com/r/skyline-stats-demo.json
- Categories: hero, chart, canvas
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/skyline-stats-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/skyline.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/skyline#skyline-stats-demo

## Files

### `registry/demos/skyline-stats-demo.tsx`

```tsx
"use client";

import * as React from "react";

import { Skyline, type SkylineTower } from "@/components/ui/skyline";

// Hours of studio time booked through Roomtone, by city.
const YEARS = {
  "2025": [
    { label: "Lisbon", value: 1420 },
    { label: "Berlin", value: 2980 },
    { label: "Lagos", value: 860 },
    { label: "Seoul", value: 3310 },
    { label: "Mexico City", value: 1890 },
    { label: "Toronto", value: 2240 },
    { label: "Melbourne", value: 1310 },
  ],
  "2026": [
    { label: "Lisbon", value: 2160 },
    { label: "Berlin", value: 3120 },
    { label: "Lagos", value: 1940 },
    { label: "Seoul", value: 4050 },
    { label: "Mexico City", value: 2460 },
    { label: "Toronto", value: 2380 },
    { label: "Melbourne", value: 1720 },
  ],
} satisfies Record<string, { label: string; value: number }[]>;

type Year = keyof typeof YEARS;

export function SkylineStatsDemo() {
  const [year, setYear] = React.useState<Year>("2026");
  const total = YEARS[year].reduce((sum, c) => sum + c.value, 0);
  const towers: SkylineTower[] = YEARS[year].map((c) => ({
    ...c,
    display: `${c.value.toLocaleString("en-US")} h · ${Math.round((c.value / total) * 100)}%`,
  }));

  return (
    <div className="w-full max-w-3xl rounded-2xl border border-zinc-950/10 bg-white p-5 text-zinc-900 shadow-sm sm:p-7 dark:border-white/10 dark:bg-zinc-950 dark:text-zinc-100">
      <div className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h3 className="font-serif text-2xl tracking-[-0.015em] sm:text-[1.75rem]">
            Where the studios were <em className="text-[#2747ff] dark:text-[#8292ff]">busiest</em>
          </h3>
          <p className="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
            Hours booked on Roomtone in {year},{" "}
            <span className="font-medium text-zinc-900 tabular-nums dark:text-zinc-100">
              {total.toLocaleString("en-US")} h
            </span>{" "}
            in all. Hover a city for its share.
          </p>
        </div>
        <div
          role="radiogroup"
          aria-label="Year"
          className="flex rounded-full border border-zinc-950/10 p-0.5 text-sm dark:border-white/10"
        >
          {(Object.keys(YEARS) as Year[]).map((y) => (
            <button
              key={y}
              type="button"
              role="radio"
              aria-checked={year === y}
              onClick={() => setYear(y)}
              className="h-8 rounded-full px-3.5 font-medium tabular-nums text-zinc-500 transition-colors duration-150 hover:text-zinc-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 aria-checked:bg-zinc-900 aria-checked:text-white dark:text-zinc-400 dark:hover:text-zinc-100 dark:focus-visible:outline-zinc-100 dark:aria-checked:bg-zinc-100 dark:aria-checked:text-zinc-900"
            >
              {y}
            </button>
          ))}
        </div>
      </div>
      <Skyline
        towers={towers}
        seed={4}
        sun={0.86}
        trees={false}
        label={`Studio hours booked by city in ${year}`}
        className="mt-6 h-72 text-zinc-900 [--skyline-sun:#ff5a1f] [--skyline-tint:#bcc7ff] sm:h-80 dark:text-zinc-100 dark:[--skyline-sun:#ff6a2b] dark:[--skyline-tint:#202c78]"
      />
    </div>
  );
}
```
