# @sabremaps/ol

> An OpenLayers source for Cloud-Optimized GeoTIFFs, rendered in the browser by sabre.

Latest version **0.0.1** (published 2026-09-23) · SEE LICENSE IN LICENSE.md license · 0 weekly downloads

## Install

```sh
npm install @sabremaps/ol
pnpm add @sabremaps/ol
yarn add @sabremaps/ol
bun add @sabremaps/ol
```

## Health

**Score 60/100 (C)** — status: active.

Positive: esm support; no vulnerabilities; recently updated; high maintenance score.

Warnings: low downloads; no types; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.0.1 |
| Published | 2026-09-23 |
| First published | 2026-09-23 |
| Weekly downloads | 0 |
| License | SEE LICENSE IN LICENSE.md |
| TypeScript types | none |
| Module format | ESM |
| Dependencies | 1 |
| Unpacked size | 13.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | michaelacohen |
| Keywords | openlayers, ol, cog, geotiff, raster, tiles, wasm |

## Links

- npm: https://www.npmjs.com/package/@sabremaps/ol
- npm.io page: https://npm.io/package/@sabremaps/ol

## Dependencies (1)

- [@sabremaps/browser](https://npm.io/package/@sabremaps/browser.md) ^0.0.1

## Alternatives

- [postcss-color-hex-alpha](https://npm.io/package/postcss-color-hex-alpha.md) — 6.4M weekly downloads
- [randomcolor](https://npm.io/package/randomcolor.md) — 348.0K weekly downloads
- [bows](https://npm.io/package/bows.md) — 1.3K weekly downloads
- [ep_prefer_color_scheme](https://npm.io/package/ep_prefer_color_scheme.md) — 260 weekly downloads
- [coc-yank](https://npm.io/package/coc-yank.md) — 61 weekly downloads

## Recent versions

- 0.0.1 (latest) — 2026-09-23

## README

# @sabremaps/ol

An OpenLayers source for Cloud-Optimized GeoTIFFs, rendered in the browser by
sabre. No tile server: the page reads
the byte ranges it needs straight from object storage and draws tiles in a
Web Worker.

```bash
npm install @sabremaps/ol ol
```

```js
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import { sabreSource } from '@sabremaps/ol';

const source = await sabreSource('https://data.example.com/farm.tif', {
  style: { colormap: 'viridis', min: 0, max: 3000 },
});

const map = new Map({
  target: 'map',
  layers: [new TileLayer({ source })],
  view: new View(),
});
map.getView().fit(source.getExtent());
```

## Styles

`style` picks one of five modes. Every field and its default is listed in the
[`@sabremaps/browser` README](https://www.npmjs.com/package/@sabremaps/browser#api).

```js
{ mode: 'colormap', colormap: 'viridis', min: 0, max: 3000 }
{ mode: 'hillshade', azimuth: 315, altitude: 45, z_factor: 1, hillshade_colormap: 'greys' }
{ mode: 'contour', colormap: 'spectral', min: 0, max: 3000, contour_level: 8 }
{ mode: 'classified', stops: [[0, '#2166ac'], [500, '#f7f7f7'], [2000, [178, 24, 43]]] }
{ mode: 'rgb', rgb_max_r: 3000, rgb_max_g: 3000, rgb_max_b: 3000 }   // three-band rasters
```

Also accepted: `nodata`, `interpolation: 'bilinear'`, `tile_size` (64 to 512),
and `mask`, a WKT polygon in WGS84 outside which pixels are transparent.

Restyle with `source.setStyle(style)`. Nothing is downloaded again: the
raster's bytes are cached in the worker, only the drawing is redone. Tiles in
the old style are dropped at once, so the layer never shows two styles side by
side. For small, continuous changes, like a slider on `max`, pass
`{ keepStale: true }` to keep old tiles on screen until their replacements
arrive.

## What it does for you

- **Draws off the main thread.** Decoding is nearly all of a tile's cost, and
  in a worker a pan never waits on it.
- **Only asks for tiles over the raster**, and past the raster's own resolution
  lets OpenLayers stretch the tiles it has instead of rendering more.
- **Drops tiles you panned away from** before rendering them.
- **Reprojects** WGS84, Web Mercator and UTM rasters into the map.
- **Shares one cache per URL**, so two layers over the same raster read it once.

Tiles are `ImageBitmap`s, so the source works under the plain canvas
`ol/layer/Tile`.

## API

`sabreSource(url, options)` resolves to a `SabreSource` once the raster's
header has been read. `options` takes `style`, `maxZoom`, and the usual
`DataTile` options such as `attributions`, `transition` and `interpolate`.

`SabreSource` adds:

| | |
| --- | --- |
| `getInfo()` | Size, bands, EPSG code, WGS84 extent, native zoom |
| `getExtent(projection?)` | The raster's extent, EPSG:3857 by default |
| `getStyle()` / `setStyle(style, { keepStale }?)` | Read or change the style |

`configure({ wasmUrl, concurrency })`, re-exported from `@sabremaps/browser`,
changes where the wasm is loaded from or how many tiles are in flight. Call it
before the first `sabreSource()`.

## Requirements

The raster must be a Cloud-Optimized GeoTIFF, and its host must allow CORS
`GET` with the `Range` header, exposing `Content-Range`. The browser blocks the
read otherwise.

Tested with OpenLayers 10.9 and Vite 8, in dev and production builds. Other
bundlers that follow the `new Worker(new URL(…, import.meta.url))` convention
(webpack 5, Rollup, esbuild, Parcel) should work, but are not yet tested.

## License

[FSL-1.1-ALv2](./LICENSE.md), included in the package. In short: use it for
anything, commercial use included, except offering it in a commercial product or
service that competes with sabre. Each release also becomes available under
Apache 2.0 two years after it ships.

---
_Source: https://npm.io/package/@sabremaps/ol · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
