Architecture
Locus is a toolkit, not a fixed dataset. It builds and serves location intelligence on top of any standard spatial grid system and any number of geographic data layers, without hardcoding one choice into the runtime. Consumers pick the grid system and the layers they need; the builder composes artifacts from pluggable source adapters; the runtime decoder stays agnostic to both.
Principles
- Consumers choose, we don't. A
GridSchemeInterfaceis the seam between "how cells are addressed" and everything built on top of it. Geohash ships first because it's what's already proven end-to-end, but it is one implementation of the interface, not the interface itself. - The builder composes from adapters, not from one hardcoded pipeline. Every external data source (Natural Earth, US Census TIGER, IANA tzdata, country-coder) is a
SourceAdapterInterfaceimplementation. Building an artifact means picking a grid scheme + a set of adapters + parameters (region bounds, precision, which layers). - The runtime decoder reads a scheme identifier, not an assumption. An artifact declares which
GridSchemeInterfaceit was built with; the decoder dispatches to the matching scheme implementation. Adding a new grid system never requires touching a consumer's code, only registering a new scheme. - No layer is mandatory. A consumer building for a single country doesn't pay for congressional-district data they'll never query. Layers are independently selectable at build time, tree-shakeable at the module level.
Grid systems
@studnicky/grid-schemes holds the GridSchemeInterface contract and every concrete scheme implementation. Both geo-data-builder and geo-resolver depend on it; neither hardcodes geohash-specific logic:
interface GridSchemeInterface {
readonly schemeId: string; // e.g. "geohash", "s2", "h3"
encode(lat: number, lon: number, precision: number): CellIdType;
decode(cellId: CellIdType): BboxType | null;
parent(cellId: CellIdType): CellIdType | null;
children(cellId: CellIdType): readonly CellIdType[];
neighbors(cellId: CellIdType): readonly CellIdType[];
covering(bbox: BboxType, maxCells?: number): readonly CellIdType[];
resolution(cellId: CellIdType): { approxEdgeMeters: number };
}| System | Structure | Strength | Status |
|---|---|---|---|
| Geohash | Base32 string, alternating lat/lon bit interleave | Human-readable, huge library ecosystem, good enough for point lookup | Shipped |
| S2 | 64-bit cell ID, quadtree over a cube-projected sphere | Best cell-shape uniformity, best-in-class cell-union covering algorithms | Planned — gated on a concrete coverage/region-query consumer |
| H3 | Hexagonal hierarchical grid, uniform 6-neighbor adjacency | Best for radius search / flood-fill / k-NN queries | Planned — gated on a concrete radius/proximity-query consumer |
Data layer taxonomy
Every layer is backed by whatever a region's own recognized system is, not a single hardcoded source. A layer like "county" isn't "US Census TIGER" — it's "whichever official administrative-division system the queried region actually publishes," with TIGER as the US implementation and other countries' systems addable later as their own implementations of the same contract.
| Layer | Source (first implementation) | Coverage |
|---|---|---|
| State/province | Natural Earth admin-1 | Global |
| County/parish | US Census TIGER/Line | US-only |
| Postal code (ZCTA) | US Census TIGER | US-only |
| Voting/electoral district | US Census TIGER | US-only |
Source adapter architecture
Two contracts separate fetch mechanics from region-specific recognition:
interface SourceAdapterInterface {
readonly sourceId: string;
readonly license: string;
fetch(params: FetchParamsType): Promise<RawDatasetType>;
readonly refreshPolicy: 'static' | 'check-for-updates';
}
interface AdministrativeSystemAdapterInterface {
readonly systemId: string; // e.g. "us-census-tiger"
readonly coverage: readonly string[]; // ISO 3166-1 alpha-2 codes this system covers
readonly layers: readonly AdminLayerType[];
fetchLayer(layer: AdminLayerType, params: FetchParamsType): Promise<RawDatasetType>;
}USCensusTigerAdapter is the first AdministrativeSystemAdapterInterface implementation (coverage: ['US']), not a special case baked into the pipeline. Adding a second region means writing a new implementation, not touching the contract or anything that already consumes it.
Package shape
One independently-loadable package per data layer — a consumer who only wants postal codes never installs country/voting-district/census code:
packages/
geo-layer-state/ @studnicky/geo-layer-state
geo-layer-county/ @studnicky/geo-layer-county
geo-layer-postal/ @studnicky/geo-layer-postal
geo-layer-voting-district/ @studnicky/geo-layer-voting-districtEach layer package depends on @studnicky/grid-schemes for cell addressing, ships its own binary artifact built by its own geo-data-builder-style pipeline, and exposes a lookup surface following the workspace's established conventions. A layer backed by an AdministrativeSystemAdapterInterface additionally exposes which systemId/region implementations it currently ships.
Further reading
The full design — grid-system tradeoffs, the phased roadmap, the data-ingest pipeline rails built on Dagonizer, and open questions on coverage and artifact shape — lives in-repo: