Thoughts on code, digital cartography, and technology.

Featured Projects

All Projects →
TRMNL Plugins
TRMNL Plugins
fullstack
maplibre
node

A variety of custom plugins for the TRMNL e-ink display.

XY Cameras
XY Cameras
webapp
duckdb
maplibre

Live public cameras across the United States featuring traffic, water and wildlife feeds.

RSSignals
RSSignals
fullstack
maplibre
node
ollama
python
sqlite

An AI-curated daily brief of the day's news, distilled from RSS feeds with a bent to progresive and tech-focused outlets.

Mapping Disasters
Mapping Disasters
fullstack
maplibre
sqlite

A map visualization of open satellite Imagery from Maxar, Capella, and Umbra.

Currently Reading

All Books →

Journal

View all →

US Forest Service OSM Mashup

· 2 min read

While scoping out my next backpacking adventure via various PDF and web maps, I ran across these US Forest Service vector tile basemaps.

Journal | Read More →
US Forest Service OSM Mashup

Using GitHub Issues as a Simple Static CMS

· 5 min read

Why use a complex CMS when you can use GitHub Issues as a lightweight blogging engine!

Journal | Read More →

A Reflection on FOSS4G North America 2025

· 3 min read

A six-hour drive each way through the hills of West Virginia to our nation’s capital might not be on everyone's to do list, but for my visit to FOSS4GNA it was definitely worth it.

Journal | Read More →
A Reflection on FOSS4G North America 2025

Refactor Web Journal

· 2 min read

I originally created this site to be a simple web 2.0 blog site with text entries for thoughts that did not fit into my work-related geospatial blog.

Journal | Read More →

Update a Git Tag

git tag -f <tag>
git push origin <tag> --force
Code | Read More →

Get Audio Info using ffmpeg

ffprobe \
  -v error \
  -select_streams a:0 \
  -show_entries stream \
  -of default=noprint_wrappers=1 \
  "input.m4a" | sed 's/=/:/'
Code | Read More →

Batch Convert Audio with ffmpeg

for f in *.flac; do ffmpeg -v warning -i "$f" -map_metadata 0 -b:a 192k "${f%.flac}.mp3"; done
Code | Read More →

Disposing an OpenLayers Map

  const layers = map.getLayers().getArray();
  layers.forEach((layer) => {
    const source = layer.getSource();
    if (source && source.dispose) {
      source.clear();
      source.dispose();
    }
    if (layer.disposeInternal) {
      layer.disposeInternal();
    } else if (layer.dispose) {
      layer.dispose();
    }
    map.removeLayer(layer);
  });
  const olCanvas = map.getViewport().querySelector("canvas");
  if (olCanvas) {
    const gl = olCanvas.getContext("webgl") || olCanvas.getContext("webgl2");
    if (gl) {
      const loseContext = gl.getExtension("WEBGL_lose_context");
      if (loseContext) {
        loseContext.loseContext();
      } 
    }
  }
  map.getInteractions().clear();
  map.getOverlays().clear();
  map.dispose();
  map.setTarget(null);
Code | Read More →

Tech Blog [Archived]

View all →

Filtering Arrays in MapLibre

· 5 min read

Techniques for Substring Matching in MapLibre GL JS and Mapbox GL JS

Tech Blog | Read More →

ShpShifter

· 5 min read

Preview, Convert, and Filter SHP, GPKG, GeoJSON & GeoParquet in the Browser

Tech Blog | Read More →

Mapping Disasters

· 6 min read

Find Open Satellite Imagery from Maxar, Capella, Umbra, and Wyvern

Tech Blog | Read More →

Palisades Fire Before and After

· 4 min read

A Sample of Available Satellite Data for Post-Disaster Visual Assessment

Tech Blog | Read More →

Deck GL and 3D Tiles

· 4 min read

Generate Colorized 3D Tiles from LiDAR and Ortho Imagery

Tech Blog | Read More →

Finding Perpendicular lines with TurfJS

· 4 min read

Bearing, LineIntersect & Destination

Tech Blog | Read More →

Photos

View all →

Folly Beach 2025

Gallery | Folly Beach 2025