What it is
ATS Ghost Fleet puts every charted shipwreck and obstruction in U.S. waters on a single map: 12,660 point features from NOAA's AWOIS (Automated Wreck and Obstruction Information System) database, served live from a public ArcGIS Online FeatureLayer and explored over the Esri Oceans basemap, whose bathymetry does the visual storytelling. The chrome is nautical-noir — ghost-cyan wrecks, amber obstructions, an ink-dark shell.
Its distinction is under the hood: every filter runs server-side through SQL definitionExpressions, including a depth-range slider that normalizes feet, meters, and fathoms to feet inside the WHERE clause itself, and a free-text search that scans vessel names and the raw survey-history narratives together. A live count chip tracks every active filter, a density heatmap toggle reveals where the seafloor is most crowded, and a 'notable wrecks' list surfaces the 110 named vessels with a recorded sinking year — USS New Jersey and USS Virginia, sunk in Billy Mitchell's 1923 aerial-bombing demonstration, both make the cut.
It rewards marine historians, wreck divers, coastal researchers, and anyone who enjoys primary-source narratives — each record carries the original AWOIS survey logbook text. It is also, for ATS, the reference demonstration of building a query-smart front end over a large hosted feature service.
The experience
On load, roughly 12,600 dots wash across the oceans basemap and the count chip reads "12,660 of 12,660". From there, every control narrows the fleet — and the chip follows:
The custom popup presents a fielded table — depth, position quality, chart number, year sunk — with graceful handling of the many nulls in a 12,660-record archival file, followed by the raw AWOIS survey-history narrative, reproduced as the surveyors wrote it.
- Wreck / obstruction segmenting. A segmented control splits the file: choose Obstructions and the chip drops to 6,402.
- Free-text search. One search box scans both vessel names and the survey-history narratives, so "submarine" or a vessel name both work.
- 'Has recorded story' toggle. Keeps only records whose survey narrative is substantive rather than a placeholder stub.
- Depth-range slider. Filters by charted depth regardless of whether the source record was measured in feet, meters, or fathoms — the units are normalized in the SQL.
- Notable wrecks. Named vessels with a recorded sinking year, ranked by the richness of their survey narrative; clicking one flies the map there and opens the popup.
- Density heatmap. A toggle swaps the class renderer for a heatmap to show concentration — harbor approaches and graveyard coasts light up immediately.
The data — where it comes from
The app carries no bundled data; everything comes live from one public feature service plus the basemap.
Data-currency caveat: the layer is a community-hosted snapshot of NOAA's archived AWOIS database, not a live NOAA service. NOAA has superseded AWOIS with the ENC Direct / wrecks-and-obstructions products. Positions inherit the original AWOIS quality codes (High / Med / Low / Poor). Not for navigation.
| Source | What it provides | Refresh | Cost | Attribution |
|---|---|---|---|---|
| NOAA AWOIS — community-hosted ArcGIS Online FeatureLayer (Wrecks_and_Obstructions, services5.arcgis.com) | 12,660 wreck/obstruction points: record number, vessel term, depth + sounding type, position quality, chart, year sunk, survey-history narrative | Static snapshot — AWOIS was archived by NOAA; histories end in the early 2010s and yearSunk tops out at 2009 | Free (public, query-only) | Credit NOAA Office of Coast Survey / AWOIS; community-hosted snapshot; not for navigation |
| Esri Oceans basemap (anonymous) | Bathymetric base that gives the wrecks their context | Vendor-managed | Free (no API key) | Esri attribution renders in-map automatically |
How it was assembled
The application is a fully static single-page app — no backend, no database, no server-side rendering. The stack: TypeScript, ArcGIS Maps SDK for JavaScript 5.0.x, Calcite Design System 5.0.x, and Vite 8.
Module map — the codebase is small and deliberate; each file owns one concern:
Key engineering decisions
- Schema forensics before code. The service schema was verified at build time (layer JSON plus sampled queries, 2026-07-12). The pivotal finding: vesselTerm doubles as vessel name and classifier — 'OBSTRUCTION' (6,402), 'UNKNOWN' (3,608), and roughly 2,416 real vessel names share one field, and no featureType field exists on this snapshot. The renderer therefore classifies with an Arcade valueExpression rather than a raw field.
- Push the work to the server. The service supports standardized SQL, verified with returnCountOnly probes: CHAR_LENGTH(), UPPER(), and arithmetic all work in WHERE clauses. The depth slider exploits this to normalize feet, meters, and fathoms to feet server-side (e.g. depth * 3.28084), so 12,660 records are filtered without shipping them to the browser.
- A meaningful 'has story' filter. A naive history-not-empty test passes 12,567 of 12,660 records — useless. The toggle uses CHAR_LENGTH(history) > 30 to drop blank and 'No History.' stubs.
- Notable-wrecks ranking. The pool is named vessels with yearSunk > 0 — 110 rows, retrieved in a single query safely under the service's 2,000-record cap — then ranked client-side by cleaned narrative length (the 254-character field truncation makes raw length server-side ranking misleading).
- Heatmap honesty. Switching to the HeatmapRenderer also disables popups: hit-testing against heatmap pixels never resolves a feature, so leaving popups on would make clicks silently no-op.
- Racing the typist. The count chip sequence-guards its queryFeatureCount responses; fast typing can otherwise return stale counts out of order.