@geoql/maplibre-gl-starfield
v0.1.1
Published
A MapLibre GL JS custom layer for rendering a Three.js starfield skybox with galaxy panorama
Maintainers
Readme
@geoql/maplibre-gl-starfield
Three.js starfield skybox custom layer for MapLibre GL JS globe projections.
Renders an optional equirectangular galaxy/milky-way panorama texture with configurable brightness, plus thousands of individual point stars with additive blending. Perfect for globe-projection maps that need a space-like background — earthquake visualizations, satellite trackers, flight paths, and more.
Installation
# npm
npm install @geoql/maplibre-gl-starfield maplibre-gl three
# pnpm
pnpm add @geoql/maplibre-gl-starfield maplibre-gl three
# yarn
yarn add @geoql/maplibre-gl-starfield maplibre-gl three
# bun
bun add @geoql/maplibre-gl-starfield maplibre-gl three
# JSR
bunx jsr add @geoql/maplibre-gl-starfieldUsage
import maplibregl from 'maplibre-gl';
import { MaplibreStarfieldLayer } from '@geoql/maplibre-gl-starfield';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
projection: { type: 'globe' },
sources: {
satellite: {
type: 'raster',
tiles: [
'https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-2020_3857/default/g/{z}/{y}/{x}.jpg',
],
tileSize: 256,
attribution: '© EOX IT Services GmbH - S2 Cloudless',
},
},
layers: [{ id: 'satellite', type: 'raster', source: 'satellite' }],
},
center: [0, 20],
zoom: 1.5,
});
map.on('load', () => {
const starfield = new MaplibreStarfieldLayer({
galaxyTextureUrl: '/milkyway.jpg', // your panorama image
galaxyBrightness: 0.35,
starCount: 4000,
starSize: 2.0,
});
// Add below all other layers so stars render behind the globe
map.addLayer(starfield, map.getStyle().layers[0]?.id);
});Options
interface MaplibreStarfieldLayerOptions {
id?: string;
starCount?: number;
starSize?: number;
starColor?: number;
galaxyTextureUrl?: string;
galaxyBrightness?: number;
}| Option | Type | Default | Description |
| ------------------ | -------- | ------------- | ------------------------------------------------------------------------------ |
| id | string | 'starfield' | Unique layer ID |
| starCount | number | 4000 | Number of individual point stars |
| starSize | number | 2.0 | Base point size for stars (randomized ±60%) |
| starColor | number | 0xffffff | Hex color for point stars |
| galaxyTextureUrl | string | undefined | URL to an equirectangular panorama image. If omitted, only point stars render. |
| galaxyBrightness | number | 0.35 | Brightness multiplier for the galaxy texture (0–1) |
Galaxy Texture
This library does not bundle a galaxy image. You need to provide your own equirectangular panorama via galaxyTextureUrl.
A great free option is the ESO/S. Brunier Milky Way panorama (source), licensed under CC BY 4.0. Download and resize to ~4096×2048 for a good balance of quality and file size:
# Download the 6000×3000 original (8 MB)
curl -o milkyway_full.jpg "https://cdn.eso.org/images/large/eso0932a.jpg"
# Resize to 4096×2048 (~3 MB)
sips --resampleWidth 4096 milkyway_full.jpg --out public/milkyway.jpgAttribution: ESO/S. Brunier — CC BY 4.0
How It Works
The layer implements MapLibre's CustomLayerInterface and shares the WebGL context with MapLibre:
- Galaxy sphere — A Three.js
SphereGeometrywithBackSiderendering, textured with the panorama image. Rendered at near-infinite depth via a vertex shader trick. - Point stars — Thousands of
Pointswith per-vertex random size and opacity, rendered with additive blending for a natural glow. - Camera sync — The projection matrix is decomposed from MapLibre's model-view-projection matrix, with translation stripped so the skybox stays at infinity regardless of zoom/pan.
Exports
// Main class
export { MaplibreStarfieldLayer } from '@geoql/maplibre-gl-starfield';
// Default export (same class)
export { default } from '@geoql/maplibre-gl-starfield';
// Types
export type { MaplibreStarfieldLayerOptions } from '@geoql/maplibre-gl-starfield';Requirements
- MapLibre GL JS >= 3.0.0
- Three.js >= 0.135.0
- Node.js >= 24.0.0
Contributing
- Fork and create a feature branch from
main - Make changes following conventional commits
- Ensure commits are signed (why?)
- Submit a PR
bun install
bun run build
bun run lint
bun run typecheck