# Frontend Contract — Subnautica2Maps 05B2

- data_version: `20260520-05b2-clean`
- frontend_unblock_ready: `true`
- marker_json_path: `/data/markers.v20260520.json` for artifact handoff; recommended app public path: `/data/markers/subnautica2maps-markers.v20260520.json` or copy this file into `public/data/markers/`.
- manifest_path: `/data/manifest.json`

## Read paths

For implementation, copy these artifacts into the frontend project public directory:

```text
public/data/markers/subnautica2maps-markers.v20260520.json
public/data/manifest.json
```

If keeping the exact task artifact names, fetch:

```ts
const markerUrl = '/data/markers.v20260520.json';
const manifestUrl = '/data/manifest.json';
```

## Marker document shape

```ts
type MarkerDocument = {
  project_slug: 'subnautica2maps';
  selected_keyword: 'subnautica 2 map';
  tenant: 'site-rerun-subnautica2maps-20260520-clean';
  schema_version: '05b-public-marker-json-v1';
  data_version: string;
  generated_at: string;
  source_policy: 'self_made_manual_or_licensed_only';
  coordinate_policy: string;
  frontend_warning: string;
  markers: Subnautica2Marker[];
}

type MarkerType = 'resource' | 'poi' | 'blueprint' | 'data_box' | 'biome' | 'wildlife' | 'plant' | 'location';
type SourceType = 'manual_gameplay' | 'official_update_note' | 'licensed_community_submission' | 'public_observation';
type Confidence = 'confirmed' | 'needs_verification' | 'deprecated';

type Subnautica2Marker = {
  marker_id: string;
  name: string;
  type: MarkerType;
  subtype: string;
  slug: string;
  coordinates: { x: number; y: number; z: number };
  depth: number | string;
  region: string;
  biome: string;
  description: string;
  route_note_from_lifepod: string;
  route_note_from_current_position_template: string;
  prerequisite_gear: string[];
  nearby_resources: string[];
  nearby_poi: string[];
  verified_game_version: string;
  source_type: SourceType;
  source_url: string | null;
  confidence: Confidence;
  updated_at: string;
  reviewer: string;
  notes: string;
  index_policy: 'index' | 'noindex';
  sitemap_eligible: boolean;
};
```

## UI rules

- Treat `confidence=needs_verification` as a visible warning: “This marker needs verification. Use it as a clue, not a final answer.”
- Do not generate sitemap entries for any marker where `sitemap_eligible=false`.
- Do not create indexable detail/resource/location pages from this release’s markers.
- Search/filter/map/detail/route/local progress can proceed because P0 tool UI can use clearly labeled unverified clues.
- Route helper runs browser-side. Never send raw current x/y/z to analytics.

## Filter taxonomy

```ts
const FILTERS = [
  { label: 'Resources', types: ['resource'] },
  { label: 'Blueprints', types: ['blueprint'] },
  { label: 'Data Boxes', types: ['data_box'] },
  { label: 'Wildlife', types: ['wildlife'] },
  { label: 'Plants', types: ['plant'] },
  { label: 'Biomes', types: ['biome'] },
  { label: 'Locations', types: ['poi', 'location'] },
] as const;
```

## Empty/error states

- Data load failed: show map shell + “Marker data could not load. Retry or check the data version.”
- No results: “No matching markers yet. Try a broader term, clear filters, or check back after the marker database is updated.”
- Low confidence: “This marker needs verification. Use the coordinates as a clue, not a final answer.”
- Route no position: “Set your current position first to calculate a route hint.”
- LocalStorage failure: “Local progress could not be saved in this browser.”

## Route helper口径

```ts
export function calculateRouteHint(current, target) {
  const dx = target.coordinates.x - current.x;
  const dy = target.coordinates.y - current.y;
  const dz = target.coordinates.z - current.z;
  const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
  return {
    distance,
    distance_bucket: distance < 250 ? '0-250' : distance < 500 ? '250-500' : distance < 1000 ? '500-1000' : '1000+',
    depth_delta: target.coordinates.y - current.y,
    direction_hint: `${dx >= 0 ? 'east' : 'west'} / ${dz >= 0 ? 'north' : 'south'}`,
  };
}
```

## Analytics endpoint / stack fallback

Preferred: Plausible custom events direct if configured. Fallback: optional `POST /api/events` proxy from 05B.

Allowed events: `pageview`, `hero_cta_click`, `tool_start`, `tool_result`, `pricing_cta_click` or support CTA equivalent, `map_search`, `marker_open`, `filter_apply`, `detail_open`, `position_set`, `route_calculate`, `progress_toggle`, `outbound_click`.

Privacy guardrails:

- `position_set`: send `coordinate_format` + `success`; no raw coordinates.
- `route_calculate`: send `marker_id`, `distance_bucket`, `success`; no raw current position.
- `map_search`: prefer controlled keyword/resource buckets.
- Do not send email/name/user_id; P0 has no auth.
