Claude
Skills
Sign in
Back

location-ar-experience

Included with Lifetime
$97 forever

Designs location-based augmented reality experiences with geospatial anchoring, GPS integration, and real-world interactive overlays.

General

What this skill does


# Location-Based AR Experience

This skill provides guidance for designing augmented reality experiences anchored to real-world locations, combining GPS, computer vision, and spatial computing.

## Core Competencies

- **Geospatial Anchoring**: GPS, geofencing, coordinate systems
- **Visual Positioning**: SLAM, image recognition, cloud anchors
- **Content Placement**: World-scale AR, occlusion, persistence
- **Mobile AR Platforms**: ARKit, ARCore, WebXR

## Location-Based AR Fundamentals

### AR Experience Types

```
┌─────────────────────────────────────────────────────────────────────┐
│                    Location-Based AR Spectrum                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  GPS-Only          Hybrid              Vision-Based                 │
│  ┌─────────┐      ┌─────────┐         ┌─────────┐                  │
│  │ ~10m    │      │ ~1m     │         │ ~1cm    │                  │
│  │accuracy │      │accuracy │         │accuracy │                  │
│  └─────────┘      └─────────┘         └─────────┘                  │
│      │                │                    │                        │
│      ▼                ▼                    ▼                        │
│  City-scale      Building-scale      Room-scale                    │
│  navigation      experiences         precision                      │
│  games           POI overlays        installations                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
```

### Accuracy Requirements by Experience Type

| Experience | Required Accuracy | Positioning Method |
|------------|-------------------|-------------------|
| City navigation | 5-15 meters | GPS |
| POI discovery | 3-5 meters | GPS + Wi-Fi |
| Building entrance | 1-2 meters | GPS + Vision |
| Indoor navigation | 0.5-1 meter | Vision + beacons |
| Object placement | 1-10 cm | Pure visual SLAM |

## Geospatial Systems

### Coordinate Systems

```python
from dataclasses import dataclass
import math

@dataclass
class GeoCoordinate:
    """WGS84 coordinate"""
    latitude: float   # -90 to 90
    longitude: float  # -180 to 180
    altitude: float = 0  # meters above sea level

    def distance_to(self, other: 'GeoCoordinate') -> float:
        """Haversine distance in meters"""
        R = 6371000  # Earth radius in meters

        lat1, lat2 = math.radians(self.latitude), math.radians(other.latitude)
        dlat = math.radians(other.latitude - self.latitude)
        dlon = math.radians(other.longitude - self.longitude)

        a = (math.sin(dlat/2)**2 +
             math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2)
        c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))

        return R * c

    def bearing_to(self, other: 'GeoCoordinate') -> float:
        """Bearing in degrees (0-360)"""
        lat1 = math.radians(self.latitude)
        lat2 = math.radians(other.latitude)
        dlon = math.radians(other.longitude - self.longitude)

        x = math.sin(dlon) * math.cos(lat2)
        y = (math.cos(lat1) * math.sin(lat2) -
             math.sin(lat1) * math.cos(lat2) * math.cos(dlon))

        bearing = math.degrees(math.atan2(x, y))
        return (bearing + 360) % 360


@dataclass
class ARWorldCoordinate:
    """Local AR coordinate (meters from origin)"""
    x: float  # East
    y: float  # Up
    z: float  # North


def geo_to_local(geo: GeoCoordinate, origin: GeoCoordinate) -> ARWorldCoordinate:
    """Convert geographic to local AR coordinates"""
    # Simplified planar projection (accurate for small areas)
    lat_scale = 111320  # meters per degree latitude
    lon_scale = 111320 * math.cos(math.radians(origin.latitude))

    x = (geo.longitude - origin.longitude) * lon_scale  # East
    z = (geo.latitude - origin.latitude) * lat_scale    # North
    y = geo.altitude - origin.altitude                   # Up

    return ARWorldCoordinate(x, y, z)
```

### Geofencing

```python
from enum import Enum
from typing import List, Callable

class GeofenceShape(Enum):
    CIRCLE = "circle"
    POLYGON = "polygon"

class Geofence:
    """Define trigger zones for AR content"""

    def __init__(self, id: str, center: GeoCoordinate, radius: float):
        self.id = id
        self.center = center
        self.radius = radius  # meters
        self.shape = GeofenceShape.CIRCLE
        self.on_enter: List[Callable] = []
        self.on_exit: List[Callable] = []
        self.on_dwell: List[Callable] = []
        self.dwell_time = 30  # seconds

    def contains(self, point: GeoCoordinate) -> bool:
        """Check if point is inside geofence"""
        return self.center.distance_to(point) <= self.radius

    def add_enter_handler(self, callback: Callable):
        self.on_enter.append(callback)


class GeofenceManager:
    """Manage multiple geofences"""

    def __init__(self):
        self.fences: dict[str, Geofence] = {}
        self.active_fences: set[str] = set()
        self.entry_times: dict[str, float] = {}

    def add_fence(self, fence: Geofence):
        self.fences[fence.id] = fence

    def update_position(self, position: GeoCoordinate, timestamp: float):
        """Check geofences and trigger callbacks"""
        currently_inside = set()

        for fence_id, fence in self.fences.items():
            if fence.contains(position):
                currently_inside.add(fence_id)

                # Trigger enter event
                if fence_id not in self.active_fences:
                    self.entry_times[fence_id] = timestamp
                    for callback in fence.on_enter:
                        callback(fence, position)

                # Check dwell time
                elif timestamp - self.entry_times[fence_id] >= fence.dwell_time:
                    for callback in fence.on_dwell:
                        callback(fence, position)

        # Trigger exit events
        for fence_id in self.active_fences - currently_inside:
            fence = self.fences[fence_id]
            for callback in fence.on_exit:
                callback(fence, position)
            del self.entry_times[fence_id]

        self.active_fences = currently_inside
```

## Visual Positioning

### ARCore Geospatial API Pattern

```kotlin
// Android/Kotlin with ARCore Geospatial API
class GeospatialManager(private val session: Session) {

    fun placeAnchorAtLocation(
        latitude: Double,
        longitude: Double,
        altitude: Double,
        heading: Float
    ): Anchor? {
        val earth = session.earth ?: return null

        // Check tracking quality
        if (earth.trackingState != TrackingState.TRACKING) {
            return null
        }

        // Check horizontal accuracy
        val pose = earth.cameraGeospatialPose
        if (pose.horizontalAccuracy > 10) {  // meters
            return null  // Not accurate enough
        }

        // Create geospatial anchor
        val quaternion = Quaternion.axisAngle(
            Vector3(0f, 1f, 0f),
            Math.toRadians(heading.toDouble()).toFloat()
        )

        return earth.createAnchor(
            latitude, longitude, altitude,
            quaternion.x, quaternion.y, quaternion.z, quaternion.w
        )
    }

    fun resolveTerrainAnchor(
        latitude: Double,
        longitude: Double,
        heading: Float,
        callback: (Anchor?) -> Unit
    ) {
        val earth = session.earth ?: return callback(null)

        // Terrain anchor automatically determines altitude
        val future = earth.resolveAnchorOnTerrainAsync(
            latitude, longitude,
            0.0,  // altitude above terrain
            /* quaternion */ 0f, 0f, 0f, 1f,
            { anchor, state ->
                when (state) {
                    Anchor.TerrainAnchorState.SUCCESS -> callback(anchor)
                    else -> callback(null

Related in General