# Skyline CTA

> A closing call to action over a city at dusk with a few windows lit. Point at "Get on board" or tab to it and the whole city switches its lights on, one window at a time; press it and a train leaves across the line.

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-cta).

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

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/skyline-cta.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 and the components it's built with: https://keyframeui.com/blocks/cta-sections/skyline-cta

## Files

### `registry/blocks/skyline-cta.tsx`

```tsx
"use client";

import * as React from "react";

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

/* ── Content ─────────────────────────────────────────────────
 * Everything you'd change to make the section yours: the
 * palette, the copy and the city. The city waits at dusk with a
 * few windows lit; point at "Get on board" (or tab to it) and
 * the whole city switches its lights on, and pressing it sends
 * a train across the line.
 * ─────────────────────────────────────────────────────────── */

/** A night band in both schemes: the page's last section ends on a city with its lights coming on. */
const PALETTE = {
  light: { paper: "#0b0d19", ink: "#f4f4f6", accent: "#8f9dff", tint: "#2a39a6", window: "#ffd27a" },
  dark: { paper: "#06070b", ink: "#f4f4f6", accent: "#8292ff", tint: "#212d82", window: "#ffd27a" },
};
/** Dark towers, a shade off the sky, so the lit windows read as light. The sun is setting. */
const TOWERS = { light: "#1d2134", dark: "#171a27" };
const SUN = "#ff6a2b";

const HEADLINE = { before: "The next train leaves", accent: "Tuesday" };
const BODY =
  "Point Milepost at your repo today and your first release rides on the next timetable. Free for teams of up to ten.";
const PRIMARY_CTA = "Get on board";
const SECONDARY_CTA = { label: "Read the timetable docs", href: "#docs" };

/** Share of the windows lit while the city waits, and once someone's boarding. */
const LIGHTS = { waiting: 0.24, boarding: 0.96 };
const CITY = { seed: 17, sun: 0.22 };

/* ── Section ─────────────────────────────────────────────── */

export function SkylineCta() {
  const [boarding, setBoarding] = React.useState(false);
  const [trains, setTrains] = React.useState(0);

  return (
    <section
      style={
        {
          "--paper-light": PALETTE.light.paper,
          "--ink-light": PALETTE.light.ink,
          "--accent-light": PALETTE.light.accent,
          "--tint-light": PALETTE.light.tint,
          "--window-light": PALETTE.light.window,
          "--towers-light": TOWERS.light,
          "--paper-dark": PALETTE.dark.paper,
          "--ink-dark": PALETTE.dark.ink,
          "--accent-dark": PALETTE.dark.accent,
          "--tint-dark": PALETTE.dark.tint,
          "--window-dark": PALETTE.dark.window,
          "--towers-dark": TOWERS.dark,
        } as React.CSSProperties
      }
      className="relative overflow-hidden bg-(--paper) text-(--ink) [--accent:var(--accent-light)] [--ink:var(--ink-light)] [--paper:var(--paper-light)] [--tint:var(--tint-light)] [--towers:var(--towers-light)] [--window:var(--window-light)] dark:[--accent:var(--accent-dark)] dark:[--ink:var(--ink-dark)] dark:[--paper:var(--paper-dark)] dark:[--tint:var(--tint-dark)] dark:[--towers:var(--towers-dark)] dark:[--window:var(--window-dark)]"
    >
      <div className="mx-auto flex max-w-2xl flex-col items-center px-6 pt-24 text-center sm:pt-28">
        <h2 className="font-serif text-4xl leading-[1.04] font-normal tracking-[-0.02em] text-balance sm:text-6xl">
          {HEADLINE.before} <em className="text-(--accent)">{HEADLINE.accent}</em>
        </h2>
        <p className="mt-5 max-w-lg text-base leading-relaxed text-pretty opacity-70 sm:text-[17px]">{BODY}</p>
        <div className="mt-8 flex flex-wrap items-center justify-center gap-x-6 gap-y-4">
          <button
            type="button"
            onPointerEnter={(e) => e.pointerType === "mouse" && setBoarding(true)}
            onPointerLeave={(e) => e.pointerType === "mouse" && setBoarding(false)}
            onFocus={() => setBoarding(true)}
            onBlur={() => setBoarding(false)}
            onClick={() => {
              setBoarding(true);
              setTrains((n) => n + 1);
            }}
            className="inline-flex h-11 items-center gap-2 rounded-full bg-(--ink) px-6 text-sm font-medium text-(--paper) transition-[opacity,scale] duration-150 hover:opacity-90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--accent) active:scale-[0.97]"
          >
            {PRIMARY_CTA}
            <svg viewBox="0 0 16 16" fill="none" aria-hidden className="size-3.5">
              <path d="M3 8h10m-4-4 4 4-4 4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </button>
          <a
            href={SECONDARY_CTA.href}
            className="rounded-sm text-sm font-medium underline decoration-current/30 underline-offset-4 transition-[text-decoration-color] duration-150 hover:decoration-current focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-(--accent)"
          >
            {SECONDARY_CTA.label}
          </a>
        </div>
      </div>
      <Skyline
        seed={CITY.seed}
        sun={CITY.sun}
        train
        headway={0}
        departures={trains}
        lights={boarding ? LIGHTS.boarding : LIGHTS.waiting}
        style={{ "--skyline-sun": SUN } as React.CSSProperties}
        className="mt-14 h-[clamp(12rem,32svh,19rem)] text-(--towers) [--skyline-light:var(--window)] [--skyline-tint:var(--tint)]"
      />
    </section>
  );
}
```
