# How to Enter and Manage Cockpit Mode in God's Eye View

> Learn how to enter and manage Cockpit mode in God's Eye View. Lock onto aircraft, hide UI, and display flight instrument data for an immersive experience.

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

---

**God's Eye View provides a dedicated Cockpit mode that locks onto a single aircraft, hides the map UI, and displays flight-instrument-style data through a coordinated system of tracking, input, and view controllers.**

The **Cockpit mode** in God's Eye View (GEV) transforms the Cesium-based viewer into an immersive flight deck interface. This self-contained UI component manages the camera, renders HUD elements, and handles keyboard shortcuts while broadcasting state changes through global events. Understanding how to enter and manage Cockpit mode requires familiarity with three core modules that coordinate the lifecycle between the tracked aircraft, user input, and DOM rendering.

## Prerequisites for Entering Cockpit Mode

Before activating Cockpit mode, the application must meet specific tracking requirements enforced by the `CockpitTrackingController` in [`src/ui/cockpitTrackingController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitTrackingController.js).

The primary prerequisite is an actively **tracked aircraft** in the Cesium viewer. The system checks that `viewer.trackedEntity` exists and has a valid `.position` property. Additionally, any custom `isEntryAllowed` callback passed to the controller must return true. The `syncEntry()` method in the tracking controller evaluates these conditions and conditionally displays the entry button (`#cockpit-entry`) in the DOM.

## Entering Cockpit Mode

Users can initiate Cockpit mode through two primary interaction paths: clicking the dedicated entry button or pressing the assigned keyboard shortcut. Both methods eventually invoke the `enter()` method in `CockpitTrackingController`.

### Using the Entry Button

When a user clicks the **Entry button** (`#cockpit-entry`), the click listener installed in `CockpitViewController` ([`src/ui/cockpitController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitController.js)) forwards the call to the tracking controller.

The `enter()` method (lines 29-33 in [`cockpitTrackingController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/cockpitTrackingController.js)) performs the following sequence:

1. Validates that the controller is not destroyed, already active, or blocked by entry restrictions.
2. Captures the current `viewer.trackedEntity` and hides the entity from the default view.
3. Stores the previously focused DOM element for restoration upon exit.
4. Disables the default Cesium camera controller (`viewer.scene.screenSpaceCameraController.enableInputs = false`).
5. Requests continuous rendering via `services.holdContinuousRender('cockpit')`.
6. Emits the `gev:cockpit-mode-changed` event with `active: true` and the aircraft identifier.

```javascript
// In CockpitViewController constructor
this._listen(this.entry, 'click', () => this.enter());

// Core entry logic in CockpitTrackingController
export function enter() {
  if (this.destroyed || this.active || !this.isEntryAllowed()) return false;
  const info = this.readAircraftInfo();
  const entity = this.viewer.trackedEntity;
  if (!info || !entity?.position) return false;

  // Store focus for later restoration
  this.entryFocusOrigin = document.activeElement instanceof HTMLElement
    ? document.activeElement
    : null;

  // Take over the camera
  this.viewer.camera.cancelFlight();
  this.trackedEntity = entity;
  this.trackedEntityWasShown = entity.show;
  entity.show = false;
  this.heading = normalizeHeading(info.track ?? 0);
  this.active = true;

  // Enable exclusive rendering & UI
  this.services.holdContinuousRender('cockpit');
  this.viewer.scene.screenSpaceCameraController.enableInputs = false;
  document.body.classList.add('cockpit-mode');
  
  this.dispatchCockpitModeChanged(true, info);
  return true;
}

```

### Using the Keyboard Shortcut

The **`c` key** toggles Cockpit mode globally when no input element has focus. The `CockpitInput` module in [`src/ui/cockpitInput.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitInput.js) captures this via `onKeyDown(event)` and forwards the command to the tracking controller. If entry criteria are satisfied, the system executes the same `enter()` sequence as the button click.

## Managing Cockpit Mode

Once active, Cockpit mode provides specialized UI controls for vision modes, context navigation, and signal streams. These interactions are managed through `CockpitViewController` and `CockpitInstruments` ([`src/ui/cockpitInstruments.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitInstruments.js)).

### Vision Mode and HUD Controls

The cockpit interface includes three vision mode buttons (`#cockpit-vision-previous`, `#cockpit-vision-current`, `#cockpit-vision-next`) that cycle through available visualization states. Clicking these triggers `cycleVisionMode(dir)` in the instruments module, which updates the HUD rendering via `setVisionMode(mode)`.

Additional management controls include:

- **TR-3B toggle** (`#tr3b-toggle`): Calls `toggleTrackedTr3b()` with UI synchronization via `syncTr3bToggle()`.
- **Context navigation**: Arrow buttons (`#cockpit-context-previous` / `#cockpit-context-next`) invoke `navigateContext(dir, {origin:'user'})` to shift situational awareness contexts.
- **Signal stream collapse**: The toggle button (`#cockpit-signal-toggle`) executes `setSignalCollapsed(!this.signalCollapsed, {user:true})` to minimize data streams.

### Keyboard Shortcuts for Panel Management

The **Escape** key serves a dual purpose within Cockpit mode. When pressed inside a specific panel (such as the context or signal stream panels), it collapses that panel and returns focus to the corresponding toggle button. When pressed with no panel active, it triggers the exit sequence.

```javascript
// In cockpitInput.js
export function onKeyDown(event) {
  if (this.destroyed) return false;
  if (event.key === 'Escape' && this.active) {
    // Collapse context panel if active
    if (this.context?.contains(event.target) && !this.contextCollapsed) {
      event.preventDefault();
      this.setContextCollapsed(true);
      this.contextToggle?.focus({preventScroll:true});
      return;
    }
    // Collapse signal panel if active
    if (this.signalStream?.contains(event.target) && !this.signalCollapsed) {
      event.preventDefault();
      this.setSignalCollapsed(true, {user:true});
      this.signalToggle?.focus({preventScroll:true});
      return;
    }
    // No panel active → exit Cockpit
    event.preventDefault();
    this.exit();
    return;
  }
}

```

## Exiting Cockpit Mode

Exiting restores the default Cesium camera controls and map interface. Users can exit via the **Map-view button** (`#map-view-switch`), pressing **Escape** (when no panels are focused), or toggling the **`c` key** again.

The `exit()` method in `CockpitTrackingController` performs cleanup in reverse order of entry:

1. Sets `this.active = false` and releases the continuous render lock (`services.releaseContinuousRender('cockpit')`).
2. Removes the `cockpit-mode` CSS class from the document body.
3. Re-enables Cesium camera inputs (`screenSpaceCameraController.enableInputs = true`).
4. Restores the previously tracked aircraft entity to its original visibility state.
5. Dispatches the `gev:cockpit-mode-changed` event with `active: false`.
6. Restores keyboard focus to the entry button or previously focused element.

```javascript
// Exit handler in CockpitViewController
this._listen(this.mapViewButton, 'click', () => this.exit());

// Core exit logic
export function exit({ restoreTracking = true } = {}) {
  if (!this.active) return false;
  const entity = this.trackedEntity;
  this.active = false;
  this.services.releaseContinuousRender('cockpit');
  document.body.classList.remove('cockpit-mode');
  this.hud?.hidden = true;
  this.viewer.scene.screenSpaceCameraController.enableInputs = true;

  // Restore the aircraft entity
  if (restoreTracking && entity && this.viewer.entities.contains(entity)) {
    entity.show = this.trackedEntityWasShown;
    this.viewer.trackedEntity = entity;
    this.restoreTrackingFrame(entity);
  }

  this.dispatchCockpitModeChanged(false);
  this.syncEntry(); // re-show the entry button if applicable
  
  // Restore focus
  const restoreTarget = this.entryFocusOrigin === this.entry
    ? this.entry
    : this.entry || this.entryFocusOrigin;
  if (restoreTarget?.isConnected && !restoreTarget.hidden) {
    restoreTarget.focus({preventScroll:true});
  }
  return true;
}

```

## Integrating with External Components

The `dispatchCockpitModeChanged` method emits the `gev:cockpit-mode-changed` event, enabling other application modules to react to state changes. The event detail includes `active` (boolean), `subjectId` (aircraft identifier), and `layerId`.

External controllers can listen for these events to hide overlays, pause background processes, or synchronize auxiliary displays:

```javascript
window.addEventListener('gev:cockpit-mode-changed', (e) => {
  const { active, subjectId, layerId } = e.detail;
  console.log(`Cockpit mode ${active ? 'entered' : 'exited'} – aircraft ${subjectId}`);
  // Hide a custom overlay when cockpit starts
  document.getElementById('my-overlay').hidden = active;
});

```

Custom callbacks such as `onEntered`, `onExited`, and `isEntryAllowed` can be injected when instantiating `CockpitViewController` to integrate with application-specific business logic.

## Summary

- **Prerequisites**: Cockpit mode requires an active `viewer.trackedEntity` with a valid position; the entry button only appears when `isEntryAllowed` returns true.
- **Entry methods**: Click the `#cockpit-entry` button or press **`c`** to invoke `enter()` in [`cockpitTrackingController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/cockpitTrackingController.js), which locks the camera and hides the entity.
- **Management**: Use vision mode buttons to cycle HUD styles, context arrows for navigation, and Escape to collapse panels; all input routes through [`cockpitInput.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/cockpitInput.js).
- **Exit paths**: Click the map-view button, press Escape (when no panel is focused), or press **`c`** again to trigger `exit()`, which restores camera controls and entity visibility.
- **Events**: The system broadcasts `gev:cockpit-mode-changed` on every transition, allowing external modules to synchronize with Cockpit state changes.

## Frequently Asked Questions

### What keyboard shortcuts are available in God's Eye View Cockpit mode?

The **`c` key** toggles Cockpit mode on and off when no input field has focus. The **Escape** key collapses focused panels (such as context or signal streams) when pressed inside them, or exits Cockpit mode entirely when pressed elsewhere. These shortcuts are captured in [`src/ui/cockpitInput.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitInput.js) and forwarded to the tracking controller for execution.

### Why is the Cockpit entry button disabled or hidden?

The entry button (`#cockpit-entry`) is controlled by the `syncEntry()` method in [`src/ui/cockpitTrackingController.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui/cockpitTrackingController.js). It requires two conditions: the Cesium viewer must have an active `trackedEntity` with a defined position property, and any custom `isEntryAllowed` callback must return true. If either condition fails, the button remains hidden or inactive.

### How do I programmatically detect when a user enters or exits Cockpit mode?

Listen for the `gev:cockpit-mode-changed` event on the window object. The event detail object contains `active` (boolean indicating entry or exit), `subjectId` (the aircraft identifier), and `layerId`. You can also pass `onEntered` and `onExited` callbacks when constructing the `CockpitViewController` instance to hook directly into the state transition logic.

### Can I customize which aircraft or entities allow Cockpit mode entry?

Yes. When creating the `CockpitViewController`, provide an `isEntryAllowed` callback function in the configuration options. This function receives the current tracked entity and aircraft info, returning `true` to permit entry or `false` to block it. The callback is evaluated in the `enter()` method before any UI transitions occur.