Skip to content

RyanHecht/skylight

 
 

Repository files navigation

Skylight

Project the aircraft passing overhead onto your ceiling, in real time — an X-ray through the roof.

Changes in this fork

User-facing tweaks made on top of upstream:

  • Planes stop blinking out on a flaky receiver — a new coast through dropouts window keeps an aircraft gliding at full brightness for a few seconds after its last fix (tunable from your phone), so a sporadic indoor antenna no longer makes planes flicker and pop back.
  • Aircraft actually draw indoors — when the radio decodes a plane's messages but never a position, the web API's real position is now used instead of being shadowed by the empty local fix.
  • Steadier labels and routes — the last-known callsign is remembered per aircraft, so flight labels and origin/destination stop flickering when the receiver briefly drops the callsign.
  • IATA flight numbers — the public flight number from your boarding pass (e.g. WN2710) now shows next to the ICAO callsign; toggle it with the new IATA # field.
  • SUPPLEMENT_MODE for the web-API supplement — choose merge (union: the API can add planes your antenna missed) or fields (the radio owns which planes appear and where; the API only backfills callsign/type so routes resolve, with no ghost aircraft).
  • Adjustable RTL-SDR gainGAIN on the dump1090 helper (default max 49.6 dB, or agc) to squeeze more range out of weak indoor reception.
  • Centered on Orlando (KMCO) — the bundled airport, runways, and labels target MCO instead of SFO.

Skylight projected on a ceiling: aircraft, trails, SFO runways and the night sky

ceiling-main.mp4

Skylight decodes ADS-B from a cheap RTL-SDR radio and renders the planes physically flying over you onto a ceiling-pointed projector. A jet you'd hear overhead glides across your ceiling at the same moment — labeled with its airline, type, and where it's headed. Pure-black background so the projector's rectangle disappears and only the aircraft (and stars) are lit.

It also draws the real sky behind the planes — sun, moon, bright stars and constellations, and live satellites including the ISS — all at their true positions for your location and time. Tune everything from your phone.

Reference build is centered on San Francisco International (SFO), but it works anywhere — set your coordinates (and swap the runway data) and you're flying.

Features

  • Real-time overhead aircraft from a local RTL-SDR (sub-second), or from a free web API with zero code changes — handy for trying it with no radio.
  • Type-aware glyphs in a luminous, swept-wing style: widebodies tower over regional jets, helicopters spin their rotors, turboprops and GA aircraft spin their props.
  • Smooth motion — interpolates the ~1 Hz fixes to 60 fps by rendering slightly in the past and tweening between real positions (no teleporting).
  • Comet trails, altitude-graded color, and range rings + compass for orientation.
  • The airport (runways) drawn at its true position, so you watch departures and arrivals line up with the runway.
  • Window to elsewhere — each routed flight shows its destination city, local time there, and miles-to-go, plus a faint great-circle arc toward where it's headed.
  • Live sky layer — sun, moon (with phase), bright stars + constellation lines, and satellites / ISS computed from TLEs. Scrub time forward/back from your phone, or jump straight to the next ISS pass.
  • Phone control panel — every setting (rotation, theme, palette, filters, sky toggles, …) is live-tunable over your LAN and persists across reboots.
  • Optional sky camera — point a PTZ camera (VISCA-over-IP + RTSP) at the sky and Skylight automatically films the planes it's projecting: ADS-B-driven pointing with latency-compensated lead prediction, an on-frame vision detector that locks the plane to center, and a confidence-gated zoom ladder that punches in as the lock holds. Includes a TV dashboard (/tv.html) with the live feed + radar inset, and a full debug UI (/tracker.html) with jog pad, target table, and a star-capture calibration wizard.
  • Appliance-ready — boots straight to a full-screen kiosk on a Raspberry Pi 5 (dual-output: projector + TV dashboard).

Hardware

Part Suggested Notes
Receiver RTL-SDR Blog V4 + dipole The included dipole is plenty — planes are nearly overhead.
Compute Raspberry Pi 5 (8 GB) Decode + render. Active cooling for 24/7.
Projector A 1080p projector pointed up Laser (e.g. Optoma GT2100HDR) gives the deepest blacks, but it's overkill — see the budget tip below.
Display link micro-HDMI → HDMI The Pi 5 uses micro-HDMI (not mini).
Mount Rotating 1/4-20 stand, pointed up Lower the stand for a bigger image; tape + a safety tether.
Sky camera (optional) Any VISCA-over-IP PTZ with RTSP (e.g. a 4K NDI conference PTZ) For the auto-filming tracker. Clamp the base rigidly — fast slews will walk an unclamped mount and ruin the aim calibration.

💡 Budget tip — you don't need an expensive projector. The pricey laser short-throw is only worth it if you want the image visible in a lit room. If you're happy viewing it in a dim/dark room (the intended vibe), a cheap native-1080p LED projector like the Yaber Buffalo Pro U9 (~$150) works great:

  • No short-throw needed — from the floor under an ~8 ft ceiling, even a 1.35:1 throw gives a ~5.5 ft image.
  • Low brightness is fine (even better) — the content is sparse-on-black, so 200–400 lumens in a dark room actually looks deeper.
  • Just verify it's native 1920×1080 (not "1080p supported"), has a quiet fan, and an HDMI input that shows on power-on.

The build: short-throw projector pointing up at the ceiling, RTL-SDR dipole antenna on the cabinet
The build — short-throw projector pointing up, RTL-SDR dipole on the cabinet.

You don't need any of this to try it — see Quick start.

Quick start (local, no radio)

Runs entirely on your computer against a free public ADS-B API.

pnpm install
DATA_SOURCE=api pnpm dev

Set your location in the control panel area is coming; for now set centerLat / centerLon in shared/src/config.ts (defaults to SFO).

With a radio (locally)

scripts/install-rtlsdr-fedora.sh    # rtl-sdr-blog driver + blacklist DVB-T (Fedora; see script for Debian)
scripts/run-dump1090-local.sh       # decode + serve aircraft.json on :8080
DATA_SOURCE=radio pnpm dev

Raspberry Pi appliance

Full walkthrough in pi-setup/README.md: flash + headless provision the SD card, install the driver + decoder + app, and set up the boot-to-kiosk display. Once it's running, push updates from your dev machine with:

PI_HOST=skylight.local ./scripts/deploy-to-pi.sh

Configuration

Config (shared/src/config.ts) is the single source of truth, persisted to server/data/config.json and live-editable from the control panel. Key fields:

centerLat / centerLon Your location — where you're looking up.
radiusMiles How far out to show (default 3 — "what you could realistically see").
rotationDeg / mirrorX Calibration for the looking-up flip (tune against a real pass).
theme ambient · telemetry · focus.
showStars / showSun / showMoon / showSatellites Sky layer toggles.
skyTimeOffsetMin Scrub the sky clock for testing (0 = live).
showDestArc / showRouteDetail "Window to elsewhere".
tracker.* The whole camera subsystem — driver (sim/visca), camera IP, mount calibration, target selection criteria, prediction/pursuit tuning, zoom + vision behavior. All live-tunable from the tracker debug UI.

Using it somewhere other than SFO: set centerLat/centerLon, and replace the runway geometry in web/src/display/airports.ts with your local airport (coordinates from OurAirports). Stars, sun, moon, and satellites are computed for your coordinates automatically.

Server environment

Env Default Meaning
DATA_SOURCE radio radio (dump1090) or api (airplanes.live)
AIRCRAFT_JSON_URL http://localhost:8080/aircraft.json dump1090 feed
SUPPLEMENT_API 1 When on radio, also poll the API (keeps landing aircraft alive)
SUPPLEMENT_MODE merge merge (union: API may add aircraft + take over stale fixes) or fields (radio owns which aircraft appear and where; API only backfills undecoded info like callsign/type so routes resolve)
PORT / HOST 3000 / 0.0.0.0 HTTP + WebSocket

Architecture

RTL-SDR ──USB──> dump1090-fa ──> aircraft.json (:8080)
                                      │ poll ~1 Hz  (+ API supplement)
                                      ▼
                         server/  (Node · Express · ws)  :3000
                         • normalize + enrich (airline/type tables + adsbdb routes)
                         • proxy satellite TLEs (Celestrak)
                         • persist config, broadcast over WebSocket
                         ├──────────────┬──────────────┬───────────────┐
                         ▼              ▼              ▼               ▼
                   Display (/)    Control (/control)  REST /api/*   tracker/  :3001
                   canvas renderer +  phone settings UI             • target selection + az/el
                   sky engine → projector (live, two-way)             lead prediction (ECEF)
                                                                    • velocity pursuit + zoom
                                                                    • vision: sky-masked blob
                                                                      detector, lag-compensated
                                                                    • VISCA-over-IP → PTZ camera
                                                                    • RTSP → H.264 passthrough
                                                                      (/video-ws) + MJPEG
                                                                    • TV dashboard + debug UI
  • shared/ — TypeScript types, config schema, and pure geo/projection/pointing math (ECEF az/el, mount model + calibration solver, alpha-beta trackers, FOV/zoom).
  • server/ — polls the radio (primary) and API (supplement), enriches aircraft, proxies TLEs, persists config, and pushes everything over a WebSocket.
  • web/ — Vite + React, four pages: the display (<canvas> renderer + celestial engine), the mobile control panel, the TV dashboard, and the tracker debug UI.
  • tracker/ — the camera brain: picks a target, predicts where it will be when the command actually bites (fix age + decode latency + motor latency), drives the PTZ with closed-loop velocity pursuit (sigma-delta speed dithering, soft limit guards, dead-reckoned pose), verifies the plane on-frame with a vision detector, and zooms in only while the lock holds. Runs against a simulator with zero hardware; replays recorded sessions deterministically for debugging.

Stack: TypeScript · React · Vite · Express · ws · pnpm workspaces · astronomy-engine · satellite.js.

Credits & data

License

MIT — be excellent, point it at the sky.

About

Project the aircraft passing overhead onto your ceiling in real time, from an RTL-SDR — with a live sky layer (sun, moon, stars, ISS) and where each plane is headed.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 91.4%
  • CSS 4.7%
  • Shell 3.3%
  • Other 0.6%