Skip to content
Back to skills

Screenshots

ASecurity

Regenerate the README screenshots (desktop + mobile) by running scripts/take_screenshots.js against a freshly-built backend and inspecting the resulting PNGs. Use when the user asks to refresh, update, or re-take the screenshots, or whenever a UI change has landed that would invalidate the current set. The script self-hosts the backend, injects a fake fleet, fetches a real aircraft photo from Wikimedia Commons, and mocks /api/aircraft + /api/blackspots + /api/stats + /api/coverage + /api/heat...

  • 55 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 26, 2026
developmentgoshellbashnodeapibackend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add MrSuttonmann/flightjar --skill screenshots --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Screenshots?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Screenshots
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mrsuttonmann-screenshots/badge)](https://www.skillsdirectory.com/skills/mrsuttonmann-screenshots)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: screenshots
description: Regenerate the README screenshots (desktop + mobile) by running scripts/take_screenshots.js against a freshly-built backend and inspecting the resulting PNGs. Use when the user asks to refresh, update, or re-take the screenshots, or whenever a UI change has landed that would invalidate the current set. The script self-hosts the backend, injects a fake fleet, fetches a real aircraft photo from Wikimedia Commons, and mocks /api/aircraft + /api/blackspots + /api/stats + /api/coverage + /api/heatmap + /api/polar_heatmap so every dialog reads like a real-world install with weeks of data.
---

# Regenerating the README screenshots

`scripts/take_screenshots.js` produces the ten PNGs under `docs/screenshots/`
(`main`, `detail-panel`, `stats`, `compact`, `blackspots` × desktop + mobile).
It runs entirely offline aside from a one-off fetch of a CC-licensed photo
from Wikimedia Commons at the start of each run: spawns a Kestrel instance
with BEAST pointed at a non-existent host, Playwright replaces
`window.WebSocket` with a no-op shim, then injects a 10-aircraft fake fleet
via `update_loop.js.update()` and mocks the endpoints the Stats dialog,
detail panel, and blackspots layer reach for.

Mocked endpoints (see the `mock*` helpers at the top of the script):

- `/api/aircraft/<hex>` → tail record with the fetched G-ZBKA 787 photo
  base64-embedded as `photo_thumbnail` / `photo_url`, plus a Creative
  Commons credit line so the screenshot attribution is honest.
- `/api/blackspots*` → dense radial grid (~few hundred cells) with three
  Gaussian "ridges" NW / NE / SE + an unreachable sprinkle at the edges
  so all four legend bands (yellow / orange / red / purple) are visible.
- `/api/stats` → 6 d 13 h uptime, 8.4 M frames, 2 WS clients, fake
  `readsb.home.lan:30005` BEAST source shown as connected.
- `/api/coverage` → 36-bucket polar coverage with an east-south-east
  lobe (~500 km max range).
- `/api/heatmap` → 7×24 traffic heatmap with morning and evening peaks
  and a weekend dip.
- `/api/polar_heatmap` → 36 × 12 reception-density grid, decaying with
  distance + brighter toward the SE lobe.

## Preferred run (backend already up)

The script takes ~30 s once the backend is warm. Boot the backend yourself
in a background shell, then point the script at it with `--base` — that way
re-runs don't pay the .NET cold-start cost each time.

```bash
# 1. One-off: build the backend so dotnet run starts quickly.
(cd dotnet && dotnet build FlightJar.slnx -c Debug)

# 2. Start the backend in the harness config. Keep the PID so you can
#    stop it cleanly after the run.
BEAST_HOST=nonexistent.invalid BEAST_PORT=1 \
  LAT_REF=51.5 LON_REF=-0.1 BEAST_OUTFILE='' \
  FLIGHT_ROUTES=0 METAR_WEATHER=0 \
  BLACKSPOTS_ENABLED=0 TELEMETRY_ENABLED=0 \
  FLIGHTJAR_STATIC_DIR=$PWD/app/static \
  dotnet dotnet/src/FlightJar.Api/bin/Debug/net10.0/FlightJar.Api.dll \
  --urls http://127.0.0.1:8766 > /tmp/flightjar.log 2>&1 &
echo $! > /tmp/flightjar.pid

# 3. Wait for readiness (usually <5 s).
until curl -sf -o /dev/null http://127.0.0.1:8766/; do sleep 0.5; done

# 4. Capture. Output lands in docs/screenshots/.
node scripts/take_screenshots.js --base http://127.0.0.1:8766

# 5. Stop the backend.
kill $(cat /tmp/flightjar.pid) 2>/dev/null
```

## All-in-one (script manages the backend)

Omit `--base` and the script spawns `dotnet run` itself. Slower (cold-build
overhead) and the `dotnet run` child may outlive the node script on
SIGTERM, so prefer the two-step flow above during iteration:

```bash
node scripts/take_screenshots.js
```

## Viewport sizing

Default viewports are `1440×900` (desktop) and `390×844` (mobile). The
detail-panel capture grows the viewport **vertically** to fit the
entire panel in a single screenshot — it measures
`#detail-panel.scrollHeight`, calls `page.setViewportSize(...)` to at
least `panelHeight + 40px`, takes the shot, then restores the nominal
viewport before the next capture. This matters most on mobile: the
Enhanced Mode S + main metric grid + altitude profile + link buttons +
stats footer together exceed the 844px default height. Any future
section added to the panel automatically gets captured in full — no
code change needed as long as the section lives inside `#detail-panel`.

If you add a **new** dialog / panel / overlay that's itself taller than
the viewport, wrap its capture the same way: measure the element's
`scrollHeight`, bump via `page.setViewportSize`, screenshot, restore.
Don't use `{ fullPage: true }` — that captures the whole scrollable
body (including the map), which is never what we want.

## After capture

1. **Read every PNG** — use the `Read` tool on each file under
   `docs/screenshots/` and check:
   - `main` + `main-mobile`: status strip reads `10 aircraft · 10
     positioned` (NOT "undefined aircraft"), 10 markers placed, sidebar
     rows populated with route + registration + type.
   - `detail-panel` + `detail-panel-mobile`: BAW283 selected, a real
     photograph of G-ZBKA at the top (not the fallback SVG), Creative
     Commons credit visible, route ticket EGLL → KSFO, telemetry grid,
     **and** the full Enhanced Mode S block (MCP alt / QNH / wind /
     OAT / TAT / Mach / IAS / TAS / GS / mag heading / true track /
     roll / turn rate / baro + IRS vertical rates). The whole panel
     should be visible top-to-bottom — if it's truncated at the
     bottom, the viewport-grow step (see "Viewport sizing") didn't
     fire correctly.
   - `stats` + `stats-mobile`: uptime / frames / rate / WS clients all
     populated (not "—"), traffic heatmap has clear peaks, polar
     coverage reports a max range ≥ 300 nm, reception-density polar
     heatmap shows a visible lobe.
   - `compact` + `compact-mobile`: sidebar hidden, map full-width,
     Leaflet layers control **collapsed** (small icon top-right, not
     the expanded list of overlay checkboxes — that's a common
     regression on mobile).
   - `blackspots` + `blackspots-mobile`: altitude slider labelled FL100
     at the right edge, dense grid of shaded cells covering most of
     the receiver radius with yellow / orange / red / purple bands all
     represented, and one cell's tooltip popped open showing
     "Blind spot at FL100 / Needs antenna ≥ X m MSL".

2. If a shot regressed (layers control expanded, blackspot tooltip
   missing, stats empty, photo didn't load, etc.), tweak
   `scripts/take_screenshots.js` and re-run. Common knobs:
   - **Fleet**: `buildFleet()` — altitudes drive marker/trail colours.
   - **Photo**: `COMMONS_PHOTO_URL`. If Wikimedia goes down the run
     falls back to `fallbackPhotoSvg()`; swap in another Commons URL if
     you need a different aircraft.
   - **Blackspot density / shape**: `mockBlackspotsGrid()` — ridge
     parameters (`cLat`, `cLon`, `peak`, `sigma`) and the `delta < 8`
     prune threshold control density.
   - **Stats realism**: `mockStatsPayload`, `mockCoveragePayload`,
     `mockHeatmapPayload`, `mockPolarHeatmapPayload`.
   - **Framing**: the explicit `state.map.setView(...)` calls inside
     each capture block. Blackspots uses zoom 8 centred on the
     receiver; main/detail rely on `update()`'s first-tick fitBounds.

## README tables

The PNGs are wired into two pairs of tables in `README.md` just under the
lede: desktop then mobile, each row containing (Overview, Detail panel,
Terrain blackspots) and (Stats dialog, Compact mode). If you add a new
capture scene to the script, add it to both tables — keep desktop and
mobile parallel so screenshots read left-to-right in the same order.

## Do not

- Do not commit `/tmp/flightjar.log` or `/tmp/flightjar.pid`.
- Do not leave a backend running after you finish — `kill` it and
  double-check with `lsof -i :8766` if you're unsure.
- Do not hand-edit the PNGs; always regenerate from the script so the
  next person with a UI change can reproduce them.
- Do not swap the Commons photo URL for a non-CC source — the detail
  panel displays the credit line straight from the mock response, so
  the attribution has to stay truthful.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.