Bruno DelorenceBruno
Appearance
Appearance

Choose your reading theme.

Contact

Edge overview

New

A dark overview of a project on an edge network: KPIs with bar sparklines, live traffic on a dotted world map, an alert you can act on, latency and deployments.

edge-overview/edge-overview.tsx
Live · interactive

copperleaf-prod

Productioncopperleaf.app

Requests

1.84B

+12.4%last 24h

p95 latency

41ms

+9 msall regions

Error rate

0.021%

+0.0065xx / requests

Cache hit ratio

94.2%

−1.1 ptedge cache

Traffic by region

Live · 1.95M req/sHealthyElevated

Regions 10

sin1 p95 is 3.3x its baseline

Since deploy #4127 at 13:41. hkg1 has 41% headroom at 36 ms.

Latency

all regions · 24h

Deployments

  1. Revert image cache key for /p/* in sin1#4131maina91e04c, live14m
  2. Cache product images at the edge for 24h#4127main3fd2b7a, raised latency3h
  3. Move /api/cart to fra1 + iad1 only#4123mainc0e1192, ready7h
  4. Bump runtime to v24 for all edge functions#4119main77ab3e0, ready12h

The live component, numbered part by part. Every measurement is read from it as it is drawn. Point at a row to outline its part, or at a part to find its row.

When to use

  • The home screen of one service served from several regions: how much traffic, how fast, how many errors, and where.
  • Health that differs by place, worth reading on a map: a region running slow stands out in red before any number is read.
  • An alert the reader can act on from where it shows, with the action’s effect drawn back on every view (map, list, KPI, chart) and an Undo.
  • Figures read over a few fixed windows (1h, 24h, 7d, 30d), where the range, a region filter and search narrow every card at once.
  • A screen that has to keep moving while it is watched: live traffic ticking, requests travelling the routes, deploys going live.

When not to use

  • A service in one region. Drop the map: four KPIs, the latency chart and the deployments say it all.
  • Digging into one incident. Use a trace or log explorer with spans, filters and a timeline; the trace here is a single request.
  • Dozens of regions or points of presence. The map’s labels collide; use a sortable table, or a map with clustered markers.
  • Business reporting (revenue, sign-ups, cohorts). Use a chart dashboard with a period picker and comparisons.
  • A status page for customers. Use a list of components with their uptime and incidents, without controls.

You can add this component with the shadcn CLI or by hand:

Into components/edge-overview of any React project, with no setup:

Terminal
npx shadcn@latest add https://brunodelorence.com/r/edge-overview.json

Either way it needs React 19 and a bundler that supports CSS Modules, such as Next.js or Vite. It has a dark colour scheme: it follows your page’s color-scheme, light unless the page sets one, or its colorScheme prop, with nothing to configure. Browsers without light-dark() show it light.

Usage

overview-page.tsx
import { EdgeOverview } from './edge-overview';export function OverviewPage() {  return (    <EdgeOverview      defaultRange="24h"      defaultRegion="all"      onShift={(shifted) => console.log(shifted ? 'shifted' : 'undone')}      onDeploy={(deployment) => console.log(deployment.id)}      autoplay={false}    />  );}

Each state below is a live instance, locked so you can study it.

The pieces it is built from, each with its measurements read live.

The overview screen of a project served from ten regions. Requests travel the routes of a dotted world map while the regions’ traffic ticks; hover a region for its popover, or click it to filter the screen. One region runs slow since a deploy: shift 30% of its traffic to a neighbour and watch its dot, its row, the KPI and the chart come back down, then undo it, or open the slow request’s trace. Time ranges, a region menu, a line legend, search and Deploy all work.

  • The window is a two-column grid: a 231 px sidebar (team switcher, sections, projects and the month’s usage meter) and a main column whose cards sit on a named grid: title, KPIs, then the map beside the regions and the latency chart beside the deployments.
  • The map is a 749 × 315 board scaled to fit its card. The land is a grid of dots, 4.35 px apart, kept where hand-drawn outlines of the continents say there is land, and painted on a canvas at the device’s pixel ratio. Each dot’s shade comes from its distance to the regions, weighted by their traffic; dots near an elevated region turn red.
  • Routes are quadratic curves; the requests travelling them are small glowing dots on the same paths through CSS offset-path, so the motion costs no script. Each region is a button with its halo and label; hovering or focusing one opens its popover with its p95 over the last hours and its stats.
  • The latency chart is drawn at the plot’s own pixel width, measured by a ResizeObserver, so strokes and dashes keep their weight. Inside the elevated band, p95 is drawn again in red over a red wash, clipped to the band; deploy markers stand on the baseline.
  • Shift 30% to hkg1 plays a two-second eased change of one number, from which every view is derived: sin1’s traffic, latency and errors, hkg1’s traffic, the p95 KPI, the chart’s bump, the dot colours and a new route from sin1 to hkg1. Undo plays it back.
  • Live, every 1.6 s the regions’ traffic moves a little: the total, the labels, the popover and the newest request bar follow. The stream and the moving requests stop offscreen, in a hidden tab and under reduced motion.
  • Layout from the component’s own width: the reference’s two columns from 1400 px, one column of cards below, an icon rail for the sidebar under 1100 px and a drawer under 720 px, where the map and the chart scroll sideways inside their cards.
  • While on screen and untouched, a demo pointer hovers regions, switches the range, reads the chart across the elevated band, opens the trace and shifts traffic, then undoes it. Any real input stops it.
  • Every colour is a light-dark() token, so the screen follows the page’s color-scheme or the colorScheme prop; the canvas reads its colours through a probe and repaints when the scheme changes.
PropTypeDefaultDescription
defaultRange'1h' | '24h' | '7d' | '30d''24h'The time range at first: it sets the KPIs, their bars and the latency chart.
defaultRegion'all' | 'iad1' | 'fra1' | 'sfo1' | 'lhr1' | 'hnd1' | 'sin1' | 'hkg1' | 'bom1' | 'gru1' | 'syd1''all'The region filter at first; the chart follows it and the other regions dim on the map.
defaultPopoverRegionCode | null'sin1'The region whose popover is open at first. The map comes back to the elevated region when the pointer leaves it; null keeps it closed.
livebooleantrueWhether traffic ticks and requests travel the routes (only on screen, never under reduced motion).
onRangeChange(range: RangeId) => void—Called with the range the reader picks.
onRegionChange(region: RegionCode | 'all') => void—Called with the region picked in the menu, on the map or in the list.
onShift(shifted: boolean) => void—Called when the alert’s action moves traffic (true) or undoes it (false).
onDeploy(deployment: Deployment) => void—Called with the new deployment when Deploy is pressed.
autoplaybooleantrueWhile on screen and untouched, a demo pointer hovers regions, switches the range, reads the chart, opens the trace and shifts traffic. Any real input stops it.
colorScheme'light' | 'dark' | 'system'—Light or dark colours, or the reader’s; without it, the page’s color-scheme.
defaultStateEdgeOverviewState—Opens in a state: { menu: "team" | "bell" | "region", trace, shifted, drawer, query, hidden: SeriesKey[], crosshair: 0–1, allRegions }. A menu opened this way leaves the focus alone; any of it turns the demo off.
classNamestring—Classes for the root, the quiet field around the window.

The complete source behind this demo. Open source under the MIT license, © 2026 Bruno Delorence: copy it, change it, ship it.

edge-overview.tsx
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';/* * Edge overview: the overview screen of a project on an edge network, dark first. An app window * with a sidebar (team switcher, sections, projects, the month's usage) and a main column: the * breadcrumbs, search and notifications; the project's title with its environment and address, * the time range, a region filter and Deploy; four KPIs with bar sparklines; traffic by region on * a dotted world map; the regions with an alert and their latency; the latency chart; and the * latest deployments. * * - Live: while the screen is on show, requests travel the map's routes, and every 1.6 s the *   regions' traffic, the total and the newest request bar move a little. * - Map: hovering or focusing a region opens its popover (p95 over the last hours, p95, requests, *   errors); clicking one filters the screen to it, as the region menu does. * - The alert: Shift 30% to hkg1 moves traffic over two seconds: sin1's latency, its dot on the *   map, its row, the KPI and the chart come back down, and a route from sin1 to hkg1 appears. *   Undo moves it back. Open trace shows the slow request's spans. * - 1h / 24h / 7d / 30d change the KPIs and the chart; the legend hides or shows each line; *   deploy markers on the chart are buttons. Search filters the regions and deployments. *   Deploy adds a deployment that builds, then goes live. * - Layout from its own width (container queries): the reference's two columns from 1400 px, *   one column of cards below; the sidebar is an icon rail under 1100 px and a drawer under
world-map.tsx
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';/* * The map of the Traffic by region card. Everything is laid out on a 749 × 315 board, which is * scaled to fit the card (never above its own size) and centred: * * - the land is a grid of dots on a canvas drawn at the device's pixel ratio. A dot's shade comes *   from how close it is to a region (weighted by that region's traffic), with a little steady *   noise, and dots around an elevated region turn red. It is drawn again only when the size or *   the regions' states change. * - the routes are quadratic curves in an SVG, and the requests travelling them are small glowing *   dots moved along the same paths by CSS offset-path, so the motion costs no script. They stop *   when the root says the screen is paused (offscreen, hidden tab, reduced motion). * - each region is a button: a dot with its halo and a label with its code and traffic. Hovering *   or focusing one opens the popover beside it, with its p95 over the last hours and its stats; *   leaving the map brings back the pinned region (the elevated one), if there is one. */import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties } from 'react';import {  ARCS,  MAP_H,
latency-chart.tsx
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';/* * The latency chart: p50, p95 and p99 over the range, drawn in an SVG at the plot's own pixel size * (measured with a ResizeObserver), so strokes and dashes keep their weight at any width. The * y scale is fixed (150 ms at the top gridline), as the reference reads, and lines may run above * it. * * The span where p95 was elevated is a tinted band with its label; inside it, p95 turns red over * a red wash. Deploy markers stand on the baseline, the bad one in red. Hovering, or focusing the * plot and pressing Left / Right, moves a crosshair with the three values of that moment. */import { useId, useLayoutEffect, useRef, useState, type KeyboardEvent } from 'react';import type { Series } from './data';import styles from './edge-overview.module.css';export type SeriesKey = 'p95' | 'p50' | 'p99';/** Card px from the plot's left edge to the axis labels' column, as on the reference. */const LEFT = 17.5;const RIGHT = 57.5;
data.ts
// Copyright (c) 2026 Bruno Delorence. MIT License./* * The made-up project behind the edge overview: its regions with their place on the map, traffic * and latency, the deployments, the KPIs of each time range, and the latency series the chart and * the popover draw. Everything is computed from a seeded random generator, so the screen is the * same on every load and on the server. * * The world map is a grid of dots kept where a hand-drawn outline of the land says there is land. * The outlines are coarse polygons in degrees of longitude and latitude, drawn for this screen. */export type RangeId = '1h' | '24h' | '7d' | '30d';export const RANGES: RangeId[] = ['1h', '24h', '7d', '30d'];export type RegionCode =  'iad1' | 'fra1' | 'sfo1' | 'lhr1' | 'hnd1' | 'sin1' | 'hkg1' | 'bom1' | 'gru1' | 'syd1';export type Region = {  code: RegionCode;  city: string;  /** Where its node sits on the 749 × 315 map. */  x: number;  y: number;
icons.tsx
// Copyright (c) 2026 Bruno Delorence. MIT License./* * The screen's line icons, drawn on a 16-unit grid with a 1.25 stroke in the current colour. They * are decorative: every control that shows one also has a name. The stylesheet sets their size. */const PATHS = {  overview: (    <>      <rect x="2.2" y="2.2" width="4.6" height="4.6" rx="1" />      <rect x="9.2" y="2.2" width="4.6" height="4.6" rx="1" />      <rect x="2.2" y="9.2" width="4.6" height="4.6" rx="1" />      <rect x="9.2" y="9.2" width="4.6" height="4.6" rx="1" />    </>  ),  rocket: (    <>      <path d="M6.3 9.7 4.1 7.5c1.6-2.9 4.6-5.4 9.6-5.4 0 5-2.5 8-5.4 9.6z" />      <path d="M6.2 6.1H3.6L2.4 7.7l1.7.6M9.9 9.8v2.6l-1.6 1.2-.6-1.7" />      <path d="M4.6 11.4c-1 .5-1.7 1.4-2 2.6 1.2-.3 2.1-1 2.6-2" />      <circle cx="10.1" cy="5.9" r="1.1" />    </>  ),
demo-pointer.tsx
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';import type { CSSProperties, Ref } from 'react';/* * The demo's pointer, and the steps that move it. A demo is a script of awaited steps: wait, or * glide the pointer somewhere. Stopping the demo (the reader takes over, or it scrolls away) ends * the step in progress at once: its promise rejects, which ends the script right there, and the * pointer fades out. * * Each glide is a curved flight played by the Web Animations API, so nothing runs frame by frame. * The points of the flight are handed to whoever wants to move along with it. The arrow and the * hand are HTML boxes that swap by their visibility: a change of style inside an SVG would lay the * SVG out again. */export type Point = { x: number; y: number };/** A glide's path and timing, for an animation that plays along with it. */export type Flight = { points: Point[]; timing: KeyframeAnimationOptions };export type Demo = {
use-autoplay.ts
// Copyright (c) 2026 Bruno Delorence. MIT License.'use client';import { useCallback, useEffect, useRef, useState } from 'react';/* * When a demo may play on its own: while part of it is on screen and the tab is visible, never * under reduced motion, and not while the reader is using it. `take()` hands it to the reader; it * takes back over `idle` ms after their last input (never, for an infinite `idle`). `visible` and * `reduced` are handed out too: the live stream runs while the screen is visible, whoever drives * it. */export function useAutoplay<T extends HTMLElement>(idle = 6000) {  const ref = useRef<T>(null);  const [visible, setVisible] = useState(false);  const [reduced, setReduced] = useState(true);  const [taken, setTaken] = useState(false);  const timer = useRef(0);  useEffect(() => {    const element = ref.current;    if (!element) return;    let onScreen = false;
edge-overview.module.css
/* Edge overview (edge-overview.tsx): an app window on a quiet field, with a sidebar and a main   column of cards.   Sizes are the screen's own px, measured on the reference at its true scale (the window is   1445 × 903 there). The layout follows the component's own width (container queries on the   root): two columns of cards from 1400 px, one below; the sidebar is an icon rail under 1100 px   and a drawer under 720 px.   Colours are the tokens below, light-dark(light, dark) where the two differ: the component takes   the color-scheme it inherits from the page (light unless the page says otherwise), or the one   its colorScheme prop sets (data-color-scheme).   Motion is transforms and opacity: the requests on the map ride an offset-path, the bars grow   by scaleY, the meters by scaleX. All of it pauses with data-paused on the root (offscreen,   hidden tab, reduced motion). */.root {  --sans: Inter, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;  --mono: JetBrains, 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;  --page: #ececee;  --frame: #fbfbfc;  --frame-edge: #dcdce0;  --rule: #e6e6ea;  --card-top: #ffffff;
  • Landmarks and headings: the sidebar is a labelled aside with a Sections nav (aria-current on the open one), the breadcrumbs are an ordered list, and every card is a section named by its heading.
  • Each region on the map is a button named with its city, code, traffic, p95 and state; focusing it opens the same popover hovering does, and pressing it filters the screen (aria-pressed).
  • The time range is a radio group with arrow keys; the team, region and notification menus are menus with arrow keys, Home, End and Escape, which hands the focus back to their button.
  • The latency chart is an image with a summary, and takes the focus: Left and Right (Shift for bigger steps), Home and End move a crosshair whose values are read out. The legend entries are toggle buttons, and deploy markers are buttons.
  • Cmd or Ctrl + K, while the focus is in the screen, goes to the search field; Escape clears it. The trace is a dialog that Escape closes, returning the focus to Open trace.
  • A polite live region says when the range or region changes, when traffic is moved or moved back, and when a deployment builds and goes live. The ticking traffic is not announced.
  • Colour is never the only signal: elevated regions say so in their names, the alert is written out, and the usage bar is a meter with its values. Moving requests, the halo pulse and the live dot stop under reduced motion; the demo pointer is hidden from assistive technology.