How to Add Custom Data Layers to God's Eye View: A Complete Implementation Guide

To add custom data layers to God's Eye View, implement the IDataLayer contract with id, name, enable(), and disable() methods, then register your module with the DataLayerManager in src/main.js.

God's Eye View is an open-source geospatial visualization platform built on Cesium that structures every live-data source as an independent module. Whether you are integrating a REST API feed, a GeoJSON dataset, or a real-time WebSocket stream, the architecture requires implementing a lightweight interface consumed by the central DataLayerManager at runtime. This guide walks through the exact contract defined in the source code and provides a production-ready implementation based on the patterns found in [src/data/manager.js](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/manager.js) and [src/main.js](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js#L4-L7).

What Is a Data-Layer Module in God's Eye View?

In God's Eye View, a data-layer module is a plain JavaScript object that encapsulates a single data source's lifecycle. The DataLayerManager (implemented in src/data/manager.js) maintains a registry of these modules, constructs the UI toggle panel, and forwards lifecycle callbacks when users enable or disable layers. Each module operates independently, managing its own Cesium data sources, timers, and network requests.

The system distinguishes between bundled layers (static GeoJSON files shipped with the app, see src/data/localLayers.js) and dynamic layers (live feeds like the flight tracking implementation in src/data/flights.js). Both types implement the same interface, ensuring consistent behavior across the application.

The IDataLayer Contract Explained

Every custom layer must expose an object adhering to the internal IDataLayer contract. The DataLayerManager validates these properties during registration in src/main.js.

Required Properties

  • id (string): A unique identifier used for toggle state persistence and UI events. This must be globally unique across all registered layers.
  • name (string): The human-readable label displayed in the data-toggle panel.
  • enable(viewer, dataManager) (function): Called when the user activates the layer. This function receives the Cesium viewer instance and should create a data source (e.g., Cesium.GeoJsonDataSource, Cesium.CzmlDataSource, or a custom BillboardCollection) and add it to the scene using viewer.scene.primitives.add().
  • disable() (function): Called when the user deactivates the layer. Must remove the data source from the scene via viewer.scene.primitives.remove() and clean up any timers, listeners, or cached data.

Optional Properties

  • description (string): Tooltip text shown on hover in the layer panel.
  • refresh(force) (function): Implements manual or forced reload logic. Useful for layers polling external APIs that need a "Refresh" button in the UI.
  • requiresKey (boolean): When set to true, the layer remains hidden in the UI until a provider key is supplied through the POWER UP panel. This gates access to premium or rate-limited APIs.

Step-by-Step Implementation Guide

Follow these steps to integrate a new data source into the God's Eye View architecture.

1. Create the Layer Module

Create a new file under src/data/ (e.g., myCustomLayer.js). This file will export a single object conforming to the IDataLayer contract. For complex integrations, refer to [src/data/flights.js](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/data/flights.js#L1-L30) as a reference implementation that handles live API polling and billboard management.

2. Implement the IDataLayer Interface

Structure your module with the mandatory properties. Use async for the enable method if fetching remote data, as the manager awaits its completion before updating the UI state.

3. Handle Data Loading and Cesium Integration

Inside enable, load your data and instantiate the appropriate Cesium data source. For API-protected endpoints, use Vite's proxy configuration (/api/...) to route requests through the development server. This keeps API keys server-side and prevents exposure in the browser, following the pattern used in src/data/flights.js for the OpenSky Network integration.

After parsing the payload, add the resulting Cesium entity collection or primitive to the scene. Store a reference to this object (typically this._source) so you can remove it later in disable.

4. Register with DataLayerManager

Import your module into [src/main.js](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/main.js#L4-L7) and register it with the DataLayerManager instance before the application initializes:

// src/main.js
import { myCustomLayer } from './data/myCustomLayer.js';

const dataManager = new DataLayerManager(viewer, { 
  allowQaRegistration: import.meta.env.DEV 
});

dataManager.register(myCustomLayer);

Alternatively, for bundled GeoJSON datasets that ship with the repository, add your layer to the array exported by src/data/localLayers.js, which uses helper utilities from src/data/createLocalGeoJsonLayer.js to generate compliant objects.

Complete Custom Layer Example

Below is a production-ready implementation that fetches a public GeoJSON feed through a Vite proxy endpoint, visualizes the data using Cesium's GeoJsonDataSource, and implements optional refresh functionality.

// src/data/myCustomLayer.js
import { GeoJsonDataSource } from 'cesium';

/**
 * Custom data-layer that visualises a public GeoJSON feed.
 * The feed is proxied through `/api/myfeed` so any required API key
 * lives only on the server side (see docs/PROXY.md for the setup).
 */
export const myCustomLayer = {
  id: 'my-custom-geojson',
  name: 'My GeoJSON Feed',
  description: 'Shows points of interest from the public XYZ API.',
  
  // Called when the user enables the layer.
  async enable(viewer) {
    // Fetch the GeoJSON via the Vite dev-server proxy.
    const response = await fetch('/api/myfeed');
    const geojson = await response.json();

    // Create a Cesium data source from the GeoJSON.
    this._source = await GeoJsonDataSource.load(geojson, {
      clampToGround: true,
      markerSize: 12,
      markerColor: Cesium.Color.YELLOW,
    });

    // Add it to the scene.
    viewer.scene.primitives.add(this._source);
  },

  // Called when the user disables the layer.
  disable() {
    if (this._source) {
      this._source.viewer.scene.primitives.remove(this._source);
      this._source = null;
    }
  },

  // Optional: expose a refresh method for a manual reload button.
  async refresh() {
    if (!this._source) return;
    await this.disable();
    await this.enable(this._source.viewer);
  },
};
// src/main.js – register the new layer
import { myCustomLayer } from './data/myCustomLayer.js';

const dataManager = new DataLayerManager(viewer, { 
  allowQaRegistration: import.meta.env.DEV 
});

dataManager.register(myCustomLayer);

Advanced Configuration Options

Proxy Configuration for API Security: When integrating third-party APIs that require authentication, configure Vite's server.proxy in vite.config.js to route requests through /api/your-endpoint. The enable function then fetches from this local proxy path, ensuring the browser never sees the actual API key. This pattern is demonstrated in src/data/flights.js for the OpenSky aviation data.

Provider Key Gating: For commercial or rate-limited data sources, set requiresKey: true in your layer object. The DataLayerManager will hide the toggle until the user enters a valid key in the POWER UP panel, at which point enable can access the stored credential securely.

Summary

  • God's Eye View uses a modular architecture where each data source implements the IDataLayer contract consumed by DataLayerManager.
  • Required methods: enable(viewer, dataManager) to create and add Cesium data sources, and disable() to clean up scene primitives and timers.
  • Registration: Import and register custom layers in src/main.js using dataManager.register(), or add bundled GeoJSON layers to src/data/localLayers.js.
  • Security: Use Vite's proxy configuration (/api/...) to keep API keys server-side when fetching external data.
  • Optional features: Implement refresh() for manual reload buttons and requiresKey for gated access to premium data sources.

Frequently Asked Questions

What Cesium data source types work with custom layers?

You can use any Cesium data source or primitive collection. Common choices include Cesium.GeoJsonDataSource for geographic features, Cesium.CzmlDataSource for time-dynamic data, Cesium.BillboardCollection for high-performance point markers, or custom Entity objects added directly to viewer.entities. The enable method receives the full viewer instance, giving you access to the entire Cesium API.

How do I protect API keys when fetching external data?

Configure Vite's development server proxy in vite.config.js to route requests (e.g., /api/opensky) to the target API. Your layer's enable method then fetches from the local proxy path (/api/opensky) rather than the external endpoint. The proxy attaches the actual API key on the server side, ensuring it never appears in browser network logs or source code, as implemented in src/data/flights.js.

Can I create layers that require user authentication?

Yes. Set the optional requiresKey: true property in your layer object. The DataLayerManager will hide the layer's toggle until the user provides a key through the POWER UP panel. Your enable method can then retrieve this key from the application's secure storage to authenticate API requests, ensuring the layer only activates after credentials are supplied.

How do I update data without requiring a full page reload?

Implement the optional refresh(force) method in your layer object. This method should re-fetch data and update the Cesium data source in place. When present, God's Eye View automatically exposes a refresh button in the layer's UI panel, allowing users to manually trigger updates or clear cached data without restarting the application.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →