Open-source project
cpaczek/skylight avatar
cpaczek/skylight

cpaczek/skylight: a ceiling projector for ADS-B aircraft and the live sky

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.

3,285 stars402 forksTypeScriptMIT

At a glance

What is it?
Skylight decodes ADS-B from an RTL-SDR and renders planes, runways, stars and satellites onto a ceiling-pointed projector. It is a Raspberry Pi appliance, not a desktop app, and the vision tracker is the part that decides which Pi you buy.
Who is it for?
Adopt Skylight if you have a dark room, a ceiling you can point a projector at, and either an RTL-SDR or a dump1090/readsb feed already on your LAN; skip it if you need a packaged desktop viewer, if the room is lit, or if you expect the vision tracker to run on a Pi 4.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 37 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What Skylight projects, and who it is actually for

Skylight turns a room into a view through the roof. It decodes ADS-B from a cheap RTL-SDR radio and draws the aircraft physically flying over your location onto a ceiling-pointed projector, labelled with airline, type and destination. The background is pure black so the projector's rectangle disappears and only the aircraft and stars are lit. Behind the planes it draws the real sky: sun, moon with phase, bright stars and constellation lines, naked-eye planets, and satellites including the ISS computed from TLEs.

The audience is narrow and specific. This is an art installation or a permanent appliance, not a tool you open on a laptop. The README's reference build is centred on San Francisco International, but the location is set in the control panel and runways are imported by ICAO or IATA code from OurAirports, so any airport works. The hardware table names an RTL-SDR Blog V4 with the included dipole, a Raspberry Pi 5 with 8 GB and active cooling, a 1080p projector pointed up, and a micro-HDMI to HDMI cable. If you do not want to buy a radio, the project also runs from a free web API with no code changes.

How the decode, interpolation and sky layers fit together

The repository is a pnpm workspace with separate server, web, shared, tracker and stream packages. The server is a small Node process; rendering is a 2D canvas in the browser. Aircraft fixes arrive at roughly 1 Hz, which would look like teleporting if drawn directly, so the display renders slightly in the past and tweens between real positions to reach 60 fps. That single design decision is what makes the motion read as flight rather than as a sequence of jumps.

The data source is switchable. With DATA_SOURCE=radio the server reads an existing dump1090 or readsb feed over HTTP at AIRCRAFT_JSON_URL; with DATA_SOURCE=api it uses the free airplanes.live feed. The URL is also runtime-tunable from the control panel's Source section, so you can point it at a decoder on your network without rebuilding. Configuration, route lookups and TLE caches persist in server/data, which the compose file mounts as a named volume.

The optional sky-camera tracker is a separate, heavier pipeline. It drives a VISCA-over-IP PTZ camera with RTSP, predicts lead to compensate for latency, and fuses three detection signals: a classical blob detector for distant specks, a large-object detector for planes directly overhead, and track-before-detect that selects targets by how they move through the world the way ADS-B predicts, on the reasoning that clouds are world-static and lose. A YOLOX-Nano ONNX model, downloaded at setup, adds a semantic airplane check. The tracker also re-fits the mount calibration from every locked pass. That is a lot of machinery, and the README is explicit that it needs a Pi 5 with 8 GB because of real-time RTSP decode plus ONNX inference.

Installing Skylight with Docker and getting a first picture

The fastest path needs no radio and no Raspberry Pi. The compose file builds the server image, which also serves the built web UI, and defaults to the free airplanes.live API. From the repository root:

bash
docker compose up -d --build

Then open http://<host>:3000/ for the display and http://<host>:3000/control for the phone control panel. The container listens on port 3000 and a healthcheck polls /api/health every 30 seconds. If nothing appears, that endpoint is the first thing to check.

To use your own receiver, edit the environment block in compose.yaml. The commented lines in the file show the shape of it:

yaml
environment:
  DATA_SOURCE: radio
  AIRCRAFT_JSON_URL: http://192.168.1.50:8080/data/aircraft.json

That URL must point at an existing dump1090 or readsb feed. The Dockerfile notes that the image contains no radio support of its own, so the decoder runs elsewhere on your network. If your decoder lives in another compose project such as ultrafeeder, the compose comments describe joining its external network so the container name resolves, then using AIRCRAFT_JSON_URL: http://ultrafeeder:8080/data/aircraft.json.

For a local development run, the root package.json exposes pnpm dev, which starts the server, web and tracker workspaces together through concurrently, and pnpm test, which runs vitest. Node 20 or newer is required. The tracker workspace is deliberately excluded from the container build, so pnpm dev on a workstation is the only way to exercise it.

Where Skylight stops being the right tool

The container path cannot run the sky-camera tracker. The Dockerfile states plainly that the image does not include sharp or onnxruntime, because that path wants direct camera and GPU access and is out of scope for a container. If auto-filming planes is the feature you came for, Docker is a dead end and you are building on a Pi 5 with the full workspace.

Hardware tiering is the second constraint, and the README is unusually blunt about it. A Pi Zero 2 W or 3B is display only; a Pi 4 handles display plus a local radio; the Pi 5 with 8 GB is for everything including vision. The suggested mitigations for weaker boards are concrete: cap maxFps at 30, trim trailSeconds, and use DATA_SOURCE=api so the Pi is not also running dump1090. One gigabyte of RAM is described as workable but tight.

There is also a physical failure mode worth taking seriously. The README warns that fast camera slews will walk an unclamped mount and ruin the aim calibration, so the PTZ base needs to be clamped rigidly. The same caution applies to the projector stand: lower it for a bigger image, but tape it and add a safety tether. Neither is a software problem you can patch later.

Skylight against a conventional ADS-B map

The obvious alternative is a browser-based flight tracker such as tar1090 or a desktop radar client fed by the same dump1090 or readsb output. Those tools are built for inspection: you pan, zoom, click an aircraft and read its full record, and they run on whatever screen you already have. Skylight inverts almost every one of those choices. It has no map to pan, it fixes the view to your own position with range rings and a compass, and it deliberately renders on black so a projector can be the display surface.

The difference that matters is the time axis. A map shows you the current state of the airspace; Skylight shows you the sky you could walk outside and look at, including the sun, moon, planets and ISS at their true positions for your location and time, with the ability to scrub time forward and back from your phone or jump to the next ISS pass. That sky layer is the part a radar client has no reason to implement. If you want to know which aircraft is overhead right now and where it is going, a map is faster and cheaper. If you want a room that shows the sky passing over the house, the map is the wrong instrument.

Maintenance, licence and upgrade cost

The project is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is the whole of the licence implication here; the repository contains no separate terms file beyond LICENSE, and nothing in the repository imposes copyleft obligations on the surrounding code.

The last push to the default branch was on 2026-08-12, and the repository is not archived. There are no retrieved releases, and package.json still carries version 0.1.0, so there is no tagged release to pin to. In practice you are tracking main. The Dockerfile pins the runtime to node:22-bookworm-slim and enables corepack so pnpm resolves to the version declared in the packageManager field, currently pnpm@10.28.2, which keeps installs reproducible across machines. The lockfile is committed, and the image build uses pnpm install --frozen-lockfile, so a rebuild will not silently drift onto newer dependency versions.

The ongoing cost is operational rather than financial. The README recommends active cooling for a Pi 5 running 24/7, and the tracker's YOLOX-Nano ONNX model is downloaded at setup, which means the vision path depends on that download remaining available. Configuration, route and TLE caches live in server/data; mounting that volume is what keeps the control panel settings across restarts.

Editorial conclusion

Adopt Skylight if you have a dark room, a ceiling you can point a projector at, and either an RTL-SDR or a dump1090/readsb feed already on your LAN; skip it if you need a packaged desktop viewer, if the room is lit, or if you expect the vision tracker to run on a Pi 4. Before buying hardware, run the compose.yaml path with DATA_SOURCE=api to confirm the render looks right from your floor position, then verify the projector is native 1920x1080 and that its HDMI input shows on power-on, since the README calls that out as a purchase criterion.

Frequently asked questions

What is cpaczek/skylight?

It is a TypeScript project that decodes ADS-B from an RTL-SDR and projects the aircraft passing overhead onto your ceiling in real time, labelled with airline, type and destination. It also draws the real sky behind them, including the sun, moon, bright stars, planets and satellites such as the ISS.

How do I install cpaczek/skylight?

The repository ships a compose.yaml that builds the server image and serves the web UI on port 3000; run docker compose up -d --build and open http://<host>:3000/. That path uses the free airplanes.live API by default, so no radio is required, and you can switch to DATA_SOURCE=radio with an AIRCRAFT_JSON_URL pointing at a dump1090 or readsb feed.

How do I use cpaczek/skylight?

Point a 1080p projector at the ceiling and open the display page, then tune every setting from the phone control panel on your LAN, including rotation, theme, palette, filters and sky toggles. Set your location there and import your airport's runways by ICAO or IATA code, since the reference build is centred on San Francisco International.

Official sources

  1. cpaczek/skylight on GitHub
  2. Issues
  3. License: MIT
  4. README
Community notes

Community notes