{"id":51769919,"url":"https://github.com/opengeos/cog-tiler-wasm","last_synced_at":"2026-07-19T23:10:05.055Z","repository":{"id":365561544,"uuid":"1272672285","full_name":"opengeos/cog-tiler-wasm","owner":"opengeos","description":"Serverless Cloud Optimized GeoTIFF (COG) dynamic tiling in WebAssembly. TiTiler-style XYZ tiles, no backend, built on whitebox-wasm.","archived":false,"fork":false,"pushed_at":"2026-07-19T21:08:40.000Z","size":349,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-19T23:08:22.784Z","etag":null,"topics":["data-science","geospatial","raster","wasm","whiteboxtools"],"latest_commit_sha":null,"homepage":"http://opengeos.org/cog-tiler-wasm","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/opengeos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-17T20:46:13.000Z","updated_at":"2026-07-19T21:08:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/opengeos/cog-tiler-wasm","commit_stats":null,"previous_names":["opengeos/cog-tiler-wasm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/opengeos/cog-tiler-wasm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opengeos%2Fcog-tiler-wasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opengeos%2Fcog-tiler-wasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opengeos%2Fcog-tiler-wasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opengeos%2Fcog-tiler-wasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/opengeos","download_url":"https://codeload.github.com/opengeos/cog-tiler-wasm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opengeos%2Fcog-tiler-wasm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35667639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-19T02:00:06.923Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-science","geospatial","raster","wasm","whiteboxtools"],"created_at":"2026-07-19T23:10:02.785Z","updated_at":"2026-07-19T23:10:05.046Z","avatar_url":"https://github.com/opengeos.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cog-tiler-wasm\n\n[![CI](https://github.com/opengeos/cog-tiler-wasm/actions/workflows/ci.yml/badge.svg)](https://github.com/opengeos/cog-tiler-wasm/actions/workflows/ci.yml)\n[![Live demo](https://img.shields.io/badge/demo-GitHub%20Pages-blue)](https://opengeos.github.io/cog-tiler-wasm/)\n\n**Serverless, TiTiler-style XYZ tiling of Cloud Optimized GeoTIFFs, in\nWebAssembly.** No backend, no GDAL, no PROJ - the map fetches COG byte ranges\ndirectly and synthesizes `z/x/y` tiles client-side.\n\n**[Live demo](https://opengeos.github.io/cog-tiler-wasm/)** - loads a sample\nEPSG:3857 COG over HTTP range requests and renders it on a MapLibre map, all in\nthe browser. Paste any CORS- and range-enabled 3857 COG URL to try your own.\n\nThis crate is the **tiling brain**. It does the slippy-map math (tile -\u003e source\npixel window), picks the right COG overview level, and renders a decoded window\ninto an RGBA tile (rescale + colormap + nodata alpha). It deliberately does\n**not** parse COGs or do network I/O - that is delegated to\n[`whitebox-wasm`](https://github.com/opengeos/whitebox-wasm)'s `CogStream`,\nwhich already implements a pure-Rust codec stack (Deflate/LZW/JPEG/WebP/…) and\nHTTP range streaming. The two compose into a complete tiler:\n\n```\n  CogStream (whitebox-wasm)               CogTiler (this crate)\n  ─────────────────────────               ─────────────────────\n  geo_transform(), levels_json()   ──▶     new(gt, w, h, epsg, nodata, levels)\n                                           pixel_window_for_tile(z,x,y) ─▶ {level,x,y,w,h}\n  tiles_for_window(level,x,y,w,h)  ◀──     (JS fetches byte ranges, decodes tiles)\n  decode_tile_f64(...)             ──▶     render(window, w, h, min, max, cmap) ─▶ RGBA\n```\n\nThe result is a TiTiler-class viewer with **zero hosting cost**: wire it to a\nMapLibre custom protocol and the browser does everything.\n\n## Why this is feasible without a server\n\nA dynamic tile server (TiTiler = FastAPI + rio-tiler + GDAL) does five things:\nread a COG by HTTP **range request**, decode the relevant internal tiles,\nresample to the requested XYZ tile, apply rescale/colormap/nodata, and encode.\nEvery one of those has a pure-Rust, WASM-clean implementation today - the two\nhistorically hard parts (a C-free codec stack and CRS handling) are already\nsolved in `whitebox-wasm`. This crate adds the thin layer on top: mercator\naddressing, overview selection, resampling, and rendering.\n\n## Status\n\n**v1 (this scaffold):** EPSG:3857 sources, single-band rendering, built-in\ncolormaps, MapLibre demo. The crate builds to `wasm32-unknown-unknown` and ships\na `wasm-pack` web package.\n\nSee [Roadmap](#roadmap) for warping, multi-band, and edge/WASI serving.\n\n## Build\n\n```bash\nrustup target add wasm32-unknown-unknown\ncargo install wasm-pack\nwasm-pack build crates/cog-tiler-wasm --release --target web --out-dir pkg\n```\n\n### Run the demo locally\n\n```bash\nnpm run dev   # builds the wasm, assembles demo/, serves http://localhost:8000/\n```\n\n`npm run dev` builds the wasm into `demo/`, copies in `cog-tiler.js` + the sample,\nand starts a zero-dependency static server with **HTTP range support** (which the\ntile streaming needs - the stdlib `python -m http.server` does not do ranges).\nSet `PORT` to change the port. No `npm install` is required (the dev scripts use\nonly Node built-ins; the demo loads its peer deps from a CDN via an import map).\n\nThe published [GitHub Pages demo](https://opengeos.github.io/cog-tiler-wasm/) is\nbuilt the same way by `.github/workflows/pages.yml`.\n\n## Usage (reusable module)\n\n[`cog-tiler.js`](cog-tiler.js) is the package's main entry. It wraps the wasm\ntiler + `whitebox-wasm` and handles EPSG:3857 sources, on-the-fly **warping** of\nany projected/4326 COG to Web Mercator, and **paletted (categorical)** rendering -\nso apps import it instead of copying the demo.\n\nIt ships **inside the npm package** (`main`/`module` -\u003e `cog-tiler.js`); the raw\nwasm tiler is also available at the `cog-tiler-wasm/wasm` subpath. Install it\nalongside its peer dependencies:\n\n```bash\nnpm install cog-tiler-wasm whitebox-wasm proj4 geotiff geotiff-geokeys-to-proj4 maplibre-gl\n```\n\n```js\nimport maplibregl from \"maplibre-gl\";\nimport { init, openCog, registerCogProtocol } from \"cog-tiler-wasm\";\n\nawait init(); // load the wasm modules once\n\nlet source = null;\n// The protocol resolves the active source + render settings per tile.\nregisterCogProtocol(maplibregl, \"cog\", () =\u003e ({\n  source,\n  render: { min: 0, max: 3000, colormap: \"viridis\" }, // ignored for paletted COGs\n}));\n\nsource = await openCog(url); // EPSG:3857 fast path, or warped if projected/4326\n// openCog also accepts a local raster: a File (e.g. from \u003cinput type=file\u003e),\n// Blob, ArrayBuffer, or Uint8Array - read in memory, no server needed.\nmap.addSource(\"cog\", { type: \"raster\", tiles: [\"cog://{z}/{x}/{y}\"], tileSize: 256 });\nmap.addLayer({ id: \"cog\", type: \"raster\", source: \"cog\" });\n\n// source.crsLabel, source.levels, source.hasPalette, source.boundsLonLat\n// and source.renderTileRGBA(z, x, y, render) / renderTilePNG(...) are also exposed.\n```\n\n### TiTiler-style COG API\n\n`CogSource` mirrors the read endpoints of\n[TiTiler's COG API](https://developmentseed.org/titiler/endpoints/cog/),\nclient-side (works on projected/paletted sources too, via the warp path):\n\n```js\n// Metadata / read\nsrc.info();           // /cog/info         -\u003e bounds, count, dtype, nodata, overviews, min/maxzoom, ...\nsrc.infoGeoJSON();    // /cog/info.geojson -\u003e GeoJSON Feature (bbox polygon + info)\nsrc.tilejson();       // /cog/tilejson.json -\u003e Mapbox TileJSON document\nawait src.point(lon, lat);          // /cog/point -\u003e band value(s) at a WGS84 coordinate\nawait src.statistics({ maxSize });  // /cog/statistics -\u003e per-band min/max/mean/std/count/\n                                    //   valid_percent/median/percentiles/histogram (from an overview)\n\n// Image generation (all accept render params below)\nawait src.previewPNG({ maxSize: 1024 });               // /cog/preview -\u003e PNG bytes\nawait src.bboxPNG([minLon, minLat, maxLon, maxLat]);   // /cog/bbox    -\u003e PNG bytes\nawait src.preview(opts);   // -\u003e { width, height, rgba }  (bbox() likewise)\n\n// Render params (on tiles, preview, bbox):\n//   bidx:     1-based bands; one -\u003e colormap/palette, three -\u003e RGB composite\n//   rescale:  [[min,max], ...] per band, or [min,max]; or min/max shorthand\n//   colormap: one of colormaps()  (viridis, magma, plasma, inferno, cividis,\n//             turbo, terrain, blues, greens, reds, rdylgn, spectral, gray)\n//   reversed: sample the colormap back-to-front (single-band)\n//   stretch:  transfer curve \"linear\" | \"sqrt\" | \"log\"  (applied after rescale)\n//   gamma:    power-law gamma (1 = off; applied after the stretch)\n//   nodata:   override the transparency value\n//   opacity:  output alpha multiplier 0..1\nawait src.renderTilePNG(z, x, y, { bidx: [4, 3, 2], rescale: [0, 3000] }); // false-color RGB\nimport { colormaps } from \"cog-tiler-wasm\";\n```\n\nThe render pipeline (nodata -\u003e rescale -\u003e stretch -\u003e gamma -\u003e colormap, plus\nreverse/opacity) matches the controls of GPU raster viewers such as\n[maplibre-gl-raster](https://github.com/opengeos/maplibre-gl-raster), so\n`cog-tiler-wasm` can serve as a CPU/WASM rendering backend for the same UI - the\npanel (band, rescale, colormap, curve, gamma, opacity) maps directly onto these\nparams and re-renders by re-requesting tiles.\n\nServer-only endpoints (`/map.html`, `WMTSCapabilities.xml`, `/validate`,\n`/stac`) are out of scope for a client-side library; band-math `expression` is\non the [roadmap](#roadmap).\n\nFor a no-build page, map the peer deps with an import map (see\n[`demo/index.html`](demo/index.html)):\n\n```html\n\u003cscript type=\"importmap\"\u003e\n  { \"imports\": {\n    \"whitebox-wasm\": \"https://esm.sh/whitebox-wasm@0.4.0\",\n    \"proj4\": \"https://esm.sh/proj4@2.20.9\",\n    \"geotiff\": \"https://esm.sh/geotiff@3.0.5\",\n    \"geotiff-geokeys-to-proj4\": \"https://esm.sh/geotiff-geokeys-to-proj4@2024.4.13\"\n  } }\n\u003c/script\u003e\n```\n\n### Low-level Rust API\n\nThe wasm crate (`CogTiler`) is the 3857 tiling brain underneath `cog-tiler.js`:\n`pixel_window_for_tile(z, x, y)` maps a tile to a source-pixel window/overview,\nand `render(window, w, h, min, max, colormap, nodata_alpha)` rasterizes an\nassembled f64 window to RGBA. See [`cog-tiler.js`](cog-tiler.js) for the\nwindow-assembly and warp loops built on top.\n\nA runnable MapLibre example (custom `cog://` protocol) is in\n[`demo/index.html`](demo/index.html).\n\n## API\n\n`version()`, `tile_bounds_3857(z, x, y) -\u003e [minx,miny,maxx,maxy]`.\n\n**`new CogTiler(geo_transform, width, height, epsg, nodata, levels_json)`**\n- `geo_transform` - 6-element GDAL affine of the full-res raster (`Float64Array`)\n- `width`/`height` - full-resolution pixel dimensions\n- `epsg` - source CRS; must be `3857` in v1\n- `nodata` - optional nodata value (`undefined`/`NaN` = none)\n- `levels_json` - JSON array of level descriptors, finest level first; only\n  `width`/`height` are read (extra `whitebox-wasm` fields are ignored)\n\nProperties: `epsg`, `num_levels`.\n\n**`pixel_window_for_tile(z, x, y)`** -\u003e `{ level, x, y, w, h, level_width, level_height, empty }`\nThe overview level and pixel window covering the tile. `empty` is true when the\ntile lies outside the raster.\n\n**`render(pixels, win_w, win_h, min, max, colormap, nodata_alpha)`** -\u003e `Uint8Array`\nA `256*256*4` RGBA tile. `pixels` is the decoded row-major `f64` window;\n`colormap` is `\"viridis\" | \"magma\" | \"terrain\" | \"gray\"`. Empty windows render\nfully transparent.\n\n## Roadmap\n\n- **TiTiler COG API parity** - done: `info`, `info.geojson`, `tilejson`,\n  `point`, `statistics`, `preview`, `bbox`, `bidx`/RGB band selection, and 13\n  colormaps (see [above](#titiler-style-cog-api)). Next: band-math\n  **`expression`** and `color_formula`.\n- **Warping** of projected/4326 sources and **paletted/categorical** rendering\n  are done in [`cog-tiler.js`](cog-tiler.js) (proj4js + geotiff.js). **Planar**\n  (`INTERLEAVE=BAND`) multi-band COGs are read per-band via geotiff.js too, since\n  whitebox-wasm's streaming decoder is chunky-only. Next: planar support\n  **upstream in `whitebox-wasm`** (and exposing its proj string + color table) to\n  drop the geotiff.js dependency, then move the warp into the Rust crate\n  (`proj4rs`).\n- **Edge / WASI serving** - run the same module as a serverless XYZ endpoint\n  near the data, not only in the browser.\n- **STAC / mosaics** - multi-asset orchestration.\n\n## Releasing\n\nThe npm package bundles the wasm tiler **and** the `cog-tiler.js` module\n(assembled by [`scripts/prepare-pkg.mjs`](scripts/prepare-pkg.mjs)). To cut a\nrelease, push a `vX.Y.Z` tag; [`release.yml`](.github/workflows/release.yml)\nbuilds, assembles, and publishes to npm via Trusted Publishing (OIDC, no token):\n\n```bash\ngit tag v0.2.0 \u0026\u0026 git push origin v0.2.0\n```\n\nOne-time setup: configure the package's Trusted Publisher on npmjs.com (package\n-\u003e Settings -\u003e Trusted Publisher) to this repo + `release.yml`.\n\n## License\n\n[MIT](LICENSE) © OpenGeos.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopengeos%2Fcog-tiler-wasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopengeos%2Fcog-tiler-wasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopengeos%2Fcog-tiler-wasm/lists"}