Claude Code Plugins

Community-maintained marketplace

Feedback

geohash-coloring

@plurigrid/asi
0
0

Geohash Coloring Skill

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name geohash-coloring
description Geohash Coloring Skill
version 1.0.0

Geohash Coloring Skill

GF(3) colored geohashes for hierarchical spatial indexing with deterministic color derivation.

Trigger

  • Geohash encoding/decoding
  • Hierarchical spatial clustering
  • Location-based coloring schemes
  • Privacy-preserving location representation

GF(3) Trit: +1 (Generator)

Generates colored spatial identifiers from coordinates.

Geohash Basics

Geohash encodes lat/lon into a string where:

  • Longer = more precise
  • Prefix = parent cell
  • Adjacent cells share prefixes
Precision | Cell Width | Cell Height
    1     |  5,009 km  |  4,992 km
    2     |  1,252 km  |    624 km
    3     |    156 km  |    156 km
    4     |     39 km  |     19 km
    5     |      5 km  |      5 km
    6     |    1.2 km  |    0.6 km
    7     |    153 m   |    153 m
    8     |     38 m   |     19 m
    9     |      5 m   |      5 m

Core Implementation

import hashlib

# Geohash alphabet (base32)
GEOHASH_CHARS = '0123456789bcdefghjkmnpqrstuvwxyz'

def encode_geohash(lat: float, lon: float, precision: int = 9) -> str:
    """Encode lat/lon to geohash string."""
    lat_range = (-90.0, 90.0)
    lon_range = (-180.0, 180.0)
    
    geohash = []
    bits = 0
    bit_count = 0
    is_lon = True
    
    while len(geohash) < precision:
        if is_lon:
            mid = (lon_range[0] + lon_range[1]) / 2
            if lon >= mid:
                bits = (bits << 1) | 1
                lon_range = (mid, lon_range[1])
            else:
                bits = bits << 1
                lon_range = (lon_range[0], mid)
        else:
            mid = (lat_range[0] + lat_range[1]) / 2
            if lat >= mid:
                bits = (bits << 1) | 1
                lat_range = (mid, lat_range[1])
            else:
                bits = bits << 1
                lat_range = (lat_range[0], mid)
        
        is_lon = not is_lon
        bit_count += 1
        
        if bit_count == 5:
            geohash.append(GEOHASH_CHARS[bits])
            bits = 0
            bit_count = 0
    
    return ''.join(geohash)

def decode_geohash(geohash: str) -> tuple[float, float, float, float]:
    """Decode geohash to bounding box (lat_min, lat_max, lon_min, lon_max)."""
    lat_range = [-90.0, 90.0]
    lon_range = [-180.0, 180.0]
    is_lon = True
    
    for char in geohash:
        idx = GEOHASH_CHARS.index(char.lower())
        for i in range(4, -1, -1):
            bit = (idx >> i) & 1
            if is_lon:
                mid = (lon_range[0] + lon_range[1]) / 2
                if bit:
                    lon_range[0] = mid
                else:
                    lon_range[1] = mid
            else:
                mid = (lat_range[0] + lat_range[1]) / 2
                if bit:
                    lat_range[0] = mid
                else:
                    lat_range[1] = mid
            is_lon = not is_lon
    
    return lat_range[0], lat_range[1], lon_range[0], lon_range[1]

def geohash_center(geohash: str) -> tuple[float, float]:
    """Get center point of geohash cell."""
    lat_min, lat_max, lon_min, lon_max = decode_geohash(geohash)
    return (lat_min + lat_max) / 2, (lon_min + lon_max) / 2

GF(3) Coloring

# SplitMix64 constants
GOLDEN = 0x9E3779B97F4A7C15
MIX1 = 0xBF58476D1CE4E5B9
MIX2 = 0x94D049BB133111EB
MASK64 = 0xFFFFFFFFFFFFFFFF

def splitmix64(seed: int) -> tuple[int, int]:
    state = (seed + GOLDEN) & MASK64
    z = state
    z = ((z ^ (z >> 30)) * MIX1) & MASK64
    z = ((z ^ (z >> 27)) * MIX2) & MASK64
    z = z ^ (z >> 31)
    return state, z

def color_geohash(geohash: str) -> dict:
    """Assign GF(3) color to geohash."""
    # Seed from geohash string
    seed = int(hashlib.sha256(geohash.encode()).hexdigest()[:16], 16)
    seed = seed & 0x7FFFFFFFFFFFFFFF
    
    _, z = splitmix64(seed)
    hue = z % 360
    
    # Trit from hue region
    if hue < 60 or hue >= 300:
        trit = 1   # Red → Generator
    elif hue < 180:
        trit = 0   # Green → Ergodic
    else:
        trit = -1  # Blue → Validator
    
    # HSL to hex
    h = hue / 360.0
    s, l = 0.7, 0.55
    c = (1 - abs(2 * l - 1)) * s
    x = c * (1 - abs((h * 6) % 2 - 1))
    m = l - c / 2
    h6 = int(h * 6)
    
    if h6 == 0: r, g, b = c, x, 0
    elif h6 == 1: r, g, b = x, c, 0
    elif h6 == 2: r, g, b = 0, c, x
    elif h6 == 3: r, g, b = 0, x, c
    elif h6 == 4: r, g, b = x, 0, c
    else: r, g, b = c, 0, x
    
    hex_color = '#{:02X}{:02X}{:02X}'.format(
        int((r + m) * 255), int((g + m) * 255), int((b + m) * 255))
    
    lat, lon = geohash_center(geohash)
    
    return {
        'geohash': geohash,
        'lat': lat,
        'lon': lon,
        'precision': len(geohash),
        'seed': seed,
        'hue': hue,
        'hex': hex_color,
        'trit': trit
    }

def colored_geohash(lat: float, lon: float, precision: int = 9) -> dict:
    """Encode and color in one step."""
    gh = encode_geohash(lat, lon, precision)
    return color_geohash(gh)

Hierarchical Coloring

def geohash_hierarchy(lat: float, lon: float, max_precision: int = 9) -> list[dict]:
    """
    Get colored geohash at all precision levels.
    Enables hierarchical spatial visualization.
    """
    full_hash = encode_geohash(lat, lon, max_precision)
    
    hierarchy = []
    for p in range(1, max_precision + 1):
        prefix = full_hash[:p]
        colored = color_geohash(prefix)
        hierarchy.append(colored)
    
    return hierarchy

def gf3_balance_at_level(geohashes: list[str]) -> dict:
    """Check GF(3) balance for a set of geohashes."""
    trit_sum = 0
    by_trit = {-1: [], 0: [], 1: []}
    
    for gh in geohashes:
        colored = color_geohash(gh)
        trit_sum += colored['trit']
        by_trit[colored['trit']].append(gh)
    
    return {
        'count': len(geohashes),
        'trit_sum': trit_sum,
        'mod3': trit_sum % 3,
        'balanced': trit_sum % 3 == 0,
        'by_trit': {
            'plus': len(by_trit[1]),
            'ergodic': len(by_trit[0]),
            'minus': len(by_trit[-1])
        }
    }

Neighbors with Color

GEOHASH_NEIGHBORS = {
    'n': {'even': 'p0r21436x8zb9dcf5h7kjnmqesgutwvy', 'odd': 'bc01fg45238967deuvhjyznpkmstqrwx'},
    's': {'even': '14365h7k9dcfesgujnmqp0r2twvyx8zb', 'odd': '238967debc01telegramuhjyznpkmstqrwx'},
    'e': {'even': 'bc01fg45238967deuvhjyznpkmstqrwx', 'odd': 'p0r21436x8zb9dcf5h7kjnmqesgutwvy'},
    'w': {'even': '238967debc01fg45uvhjyznpkmstqrwx', 'odd': '14365h7k9dcfesgujnmqp0r2twvyx8zb'}
}

def geohash_neighbors(geohash: str) -> dict:
    """Get 8 neighbors with colors."""
    directions = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw']
    neighbors = {}
    
    # Simplified: compute from center with offset
    lat, lon = geohash_center(geohash)
    precision = len(geohash)
    
    # Approximate cell size
    lat_delta = 180 / (2 ** (precision * 2.5))
    lon_delta = 360 / (2 ** (precision * 2.5))
    
    offsets = {
        'n': (lat_delta, 0),
        'ne': (lat_delta, lon_delta),
        'e': (0, lon_delta),
        'se': (-lat_delta, lon_delta),
        's': (-lat_delta, 0),
        'sw': (-lat_delta, -lon_delta),
        'w': (0, -lon_delta),
        'nw': (lat_delta, -lon_delta)
    }
    
    for direction, (dlat, dlon) in offsets.items():
        neighbor_lat = lat + dlat
        neighbor_lon = lon + dlon
        neighbor_gh = encode_geohash(neighbor_lat, neighbor_lon, precision)
        neighbors[direction] = color_geohash(neighbor_gh)
    
    return neighbors

def neighbor_gf3_analysis(geohash: str) -> dict:
    """Analyze GF(3) distribution of cell and neighbors."""
    center = color_geohash(geohash)
    neighbors = geohash_neighbors(geohash)
    
    all_trits = [center['trit']] + [n['trit'] for n in neighbors.values()]
    
    return {
        'center': center,
        'neighbors': neighbors,
        'total_cells': 9,
        'trit_sum': sum(all_trits),
        'mod3': sum(all_trits) % 3,
        'distribution': {
            'plus': all_trits.count(1),
            'ergodic': all_trits.count(0),
            'minus': all_trits.count(-1)
        }
    }

DuckDB Integration

-- Create colored geohash table
CREATE TABLE location_hashes (
    location_id VARCHAR,
    geohash VARCHAR,
    precision INTEGER,
    lat DOUBLE,
    lon DOUBLE,
    seed BIGINT,
    gay_color VARCHAR,
    gf3_trit INTEGER
);

-- Aggregate by geohash prefix (clustering)
SELECT 
    LEFT(geohash, 4) as cluster,
    COUNT(*) as count,
    SUM(gf3_trit) as trit_sum,
    SUM(gf3_trit) % 3 as gf3_balance
FROM location_hashes
GROUP BY LEFT(geohash, 4)
HAVING COUNT(*) > 10
ORDER BY count DESC;

-- Find balanced clusters
SELECT cluster, count, trit_sum
FROM (
    SELECT 
        LEFT(geohash, 5) as cluster,
        COUNT(*) as count,
        SUM(gf3_trit) as trit_sum
    FROM location_hashes
    GROUP BY LEFT(geohash, 5)
)
WHERE trit_sum % 3 = 0;

Triads

geohash-coloring (+1) ⊗ duckdb-spatial (0) ⊗ osm-topology (-1) = 0 ✓
geohash-coloring (+1) ⊗ geodesic-manifold (0) ⊗ map-projection (-1) = 0 ✓
geohash-coloring (+1) ⊗ acsets (0) ⊗ three-match (-1) = 0 ✓

References

  • Geohash.org specification
  • H3 hexagonal alternative (Uber)
  • S2 geometry (Google)

Scientific Skill Interleaving

This skill connects to the K-Dense-AI/claude-scientific-skills ecosystem:

Geospatial

  • geopandas [○] via bicomodule

Visualization

  • matplotlib [○] via bicomodule
    • Hub for all visualization

Bibliography References

  • cryptography: 1 citations in bib.duckdb

Cat# Integration

This skill maps to Cat# = Comod(P) as a bicomodule in the equipment structure:

Trit: 0 (ERGODIC)
Home: Prof
Poly Op: ⊗
Kan Role: Adj
Color: #26D826

GF(3) Naturality

The skill participates in triads satisfying:

(-1) + (0) + (+1) ≡ 0 (mod 3)

This ensures compositional coherence in the Cat# equipment structure.