# God's Eye View Data Layer Interface: Complete Implementation Guide

> Explore the God's Eye View data layer interface a plain JavaScript contract with init enable disable update and destroy methods for seamless integration. Get stats too.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: how-to-guide
- Published: 2026-09-06

---

**The God's Eye View data layer interface is a plain JavaScript contract consisting of `init(viewer, options?)`, `enable()`, `disable()`, `update(dt)`, `destroy()`, and an optional `getStats()` method that every visual layer must implement.**

Every dataset rendered in God's Eye View—whether traffic, CCTV feeds, flights, or satellites—conforms to this unified interface. The architecture decouples data sources from the rendering engine, allowing the **layer manager** to treat all visual layers identically. This guide examines the interface specification, walks through concrete implementations, and shows how to create custom layers.

## Core Interface Methods

The data layer interface requires five mandatory methods and one optional method. These are defined in the header comment of [`src/data/traffic.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/traffic.js) and enforced by convention across all layer files.

### `init(viewer, options?)`

Asynchronously initializes the layer's internal state and attaches it to the Cesium viewer.

- **Parameters:** `viewer` (the global Cesium viewer instance), optional `options` object
- **Returns:** `Promise<void>` or `void`
- **Purpose:** Create entities, set up network connections, configure initial state

```javascript
// From src/data/traffic.js - typical init pattern
async init(viewer, options = {}) {
  this.viewer = viewer;
  this.signal = options.signal; // AbortController for cancellation
  this.entities = [];
  // ... fetch initial data, create Cesium entities
}

```

### `enable()`

Activates the layer for visibility. Called after `init()` completes successfully.

- Transitions layer from initialized to active state
- Typically sets `entity.show = true` or starts animations
- Must be idempotent (safe to call multiple times)

### `disable()`

Deactivates the layer without destroying resources.

- Hides visual elements: `entity.show = false`
- Pauses network polling or data updates
- Preserves state for quick re-enabling

### `update(dt)`

Called on every animation frame with elapsed time in milliseconds.

- **Parameter:** `dt` — delta time since last frame in milliseconds
- **Use cases:** animate entities, fetch fresh data, cull distant features, update labels

```javascript
update(dt) {
  // Throttle network updates
  this.accumulator += dt;
  if (this.accumulator > 5000) { // Every 5 seconds
    this.fetchNewData();
    this.accumulator = 0;
  }
  // Animate existing entities based on dt
  this.entities.forEach(e => e.updatePosition(dt));
}

```

### `destroy()`

Synchronously or asynchronously cleans up all resources.

- Removes Cesium entities: `viewer.entities.remove(this.entity)`
- Aborts pending `fetch()` requests via `AbortController`
- Clears timers, event listeners, and WebGL resources
- Must be safe to call even if `init()` failed partially

### `getStats()` (Optional)

Returns a diagnostic object for debugging and performance monitoring.

```javascript
getStats() {
  return {
    entityCount: this.entities.length,
    lastFetch: this.lastFetchTime,
    bytesTransferred: this.totalBytes,
    errorCount: this.errors.length
  };
}

```

## Layer Manager Integration

The **layer manager** at [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) orchestrates all registered layers by invoking interface methods in strict order.

### Lifecycle Sequence

```javascript
import layerManager from "./data/manager.js";

// 1. Initialize all registered layers
await layerManager.loadAll(viewer);

// 2. Enable specific layer
layerManager.enable("traffic");

// 3. Per-frame updates (called in render loop)
layerManager.updateAll(deltaTime);

// 4. Disable when hidden
layerManager.disable("traffic");

// 5. Cleanup on application exit
await layerManager.destroyAll();

```

### Internal Manager Implementation

```javascript
// src/data/manager.js - simplified excerpt
const layerRegistry = {
  traffic: () => import("./traffic.js"),
  cctv: () => import("./cctv.js"),
  flights: () => import("./flights.js"),
  // ... additional layers
};

class LayerManager {
  async loadAll(viewer, options = {}) {
    for (const [name, loader] of Object.entries(layerRegistry)) {
      const module = await loader();
      const layer = module.default;
      await layer.init(viewer, { signal: options.signal });
      this.layers.set(name, layer);
    }
  }

  enable(name) {
    const layer = this.layers.get(name);
    if (layer?.enable) layer.enable();
  }

  disable(name) {
    const layer = this.layers.get(name);
    if (layer?.disable) layer.disable();
  }

  updateAll(dt) {
    for (const layer of this.layers.values()) {
      if (layer.update) layer.update(dt);
    }
  }

  async destroyAll() {
    for (const [name, layer] of this.layers) {
      await layer.destroy?.();
      this.layers.delete(name);
    }
  }

  getStats(name) {
    return this.layers.get(name)?.getStats?.();
  }
}

```

## Built-In Layer Implementations

God's Eye View ships with several reference implementations demonstrating the interface in production contexts.

### Traffic Layer ([`src/data/traffic.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/traffic.js))

The primary example documented in source comments. Implements real-time vehicle tracking with:

- WebSocket connection for live position updates
- Entity pooling to minimize garbage collection
- Distance-based LOD (level-of-detail) rendering

### CCTV Layer ([`src/data/cctv.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/cctv.js))

Surveillance camera feeds using:

- Video texture projection onto Cesium polygons
- Frustum visualization for camera sight lines
- Modal/popup integration on click events

### Flights Layer ([`src/data/flights.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/flights.js))

Aircraft tracking via ADS-B data:

- Great-circle interpolation between position reports
- Altitude-based coloring and scaling
- Trail/ghost rendering for flight paths

## Creating Custom Data Layers

Any JavaScript module exporting an object with the interface methods can be registered as a layer.

### Complete Custom Layer Example

```javascript
// src/data/weatherRadar.js
export default {
  // Internal state
  viewer: null,
  entities: [],
  lastUpdate: 0,
  rotation: 0,

  async init(viewer, options = {}) {
    this.viewer = viewer;
    this.signal = options.signal;
    
    // Create radar sweep entity
    this.sweepEntity = viewer.entities.add({
      name: "Weather Radar",
      position: Cesium.Cartesian3.fromDegrees(-95.7129, 37.0902, 0),
      ellipse: {
        semiMinorAxis: 100000, // 100km radius
        semiMajorAxis: 100000,
        material: new Cesium.ColorMaterialProperty(
          new Cesium.Color(0.0, 0.6, 1.0, 0.3)
        ),
        rotation: new Cesium.CallbackProperty(() => this.rotation, false)
      }
    });
    
    this.entities.push(this.sweepEntity);
    await this.fetchRadarData();
  },

  enable() {
    this.entities.forEach(e => e.show = true);
    this.active = true;
  },

  disable() {
    this.entities.forEach(e => e.show = false);
    this.active = false;
  },

  update(dt) {
    if (!this.active) return;
    
    // Animate radar sweep rotation
    this.rotation += dt * 0.001; // 1 radian per second
    
    // Poll for new data every 5 minutes
    this.lastUpdate += dt;
    if (this.lastUpdate > 300000) {
      this.fetchRadarData().catch(console.error);
      this.lastUpdate = 0;
    }
  },

  async fetchRadarData() {
    const response = await fetch("/api/weather/radar", {
      signal: this.signal
    });
    const data = await response.json();
    // Update entity appearances based on precipitation intensity
    this.updateVisualization(data);
  },

  updateVisualization(data) {
    // Implementation: color mapping based on dBZ values
  },

  async destroy() {
    // Clean up entities
    for (const entity of this.entities) {
      this.viewer.entities.remove(entity);
    }
    this.entities = [];
    
    // Abort any pending fetches
    if (this.signal?.abort) {
      this.signal.abort();
    }
  },

  getStats() {
    return {
      entityCount: this.entities.length,
      sweepAngleRad: this.rotation,
      sweepAngleDeg: Cesium.Math.toDegrees(this.rotation) % 360,
      lastDataFetch: this.lastUpdate
    };
  }
};

```

### Registration in Layer Manager

```javascript
// src/data/manager.js - add to registry
import weatherRadar from "./weatherRadar.js";

const layerRegistry = {
  traffic: () => import("./traffic.js"),
  cctv: () => import("./cctv.js"),
  flights: () => import("./flights.js"),
  satellites: () => import("./satellites.js"),
  weatherRadar, // Static import for custom layer
};

```

## Error Handling and Edge Cases

Robust layer implementations follow these patterns found in [`src/data/traffic.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/traffic.js):

- **Defensive `init()`:** Check for Cesium viewer availability, handle missing WebGL contexts
- **Graceful `destroy()`:** Use optional chaining (`this.entity?.remove()`) to handle partial initialization
- **`update()` throttling:** Prevent frame drops from synchronous network I/O
- **AbortController integration:** Pass `signal` through all `fetch()` calls for cancellation on layer disable

## Summary

- **God's Eye View data layer interface** mandates five methods—`init()`, `enable()`, `disable()`, `update(dt)`, `destroy()`—plus optional `getStats()`
- The **layer manager** in [`src/data/manager.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) orchestrates lifecycle across all registered layers uniformly
- **Built-in layers** ([`traffic.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/traffic.js), [`cctv.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/cctv.js), [`flights.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/flights.js)) serve as reference implementations of production-quality code
- **Custom layers** require only a plain JavaScript object with the interface methods; no inheritance or framework classes needed
- The architecture enables **hot-swappable data sources** without modifying core rendering or application logic

## Frequently Asked Questions

### What happens if a layer doesn't implement all required methods?

The layer manager defensively checks for method existence before invocation (`layer.update?.(dt)`), so missing methods are silently skipped. However, omitting `init()` or `destroy()` typically causes runtime errors or resource leaks. Always implement all five core methods for reliable operation.

### Can data layers use async/await throughout their lifecycle?

Yes. `init()` and `destroy()` support async operations natively. The `update()` method may also be async, though the manager does not await its completion to maintain frame rate—fire-and-forget patterns with `Promise.catch()` are recommended for network calls inside `update()`.

### How does God's Eye View handle layer performance monitoring?

The optional `getStats()` method returns diagnostic objects consumed by the debug UI. Built-in layers expose entity counts, network latency, and memory usage. Aggregate statistics across all active layers are available via `layerManager.getAllStats()` for identifying bottlenecks.

### Is TypeScript support available for the data layer interface?

The codebase uses pure JavaScript without type definitions. For TypeScript projects, you can define the interface as:

```typescript
interface DataLayer {
  init(viewer: Viewer, options?: { signal?: AbortSignal }): Promise<void> | void;
  enable(): void;
  disable(): void;
  update(dt: number): void;
  destroy(): Promise<void> | void;
  getStats?(): Record<string, unknown>;
}

```