# What Is the Scope Mask in God's Eye View? Circular Viewport Feature Explained

> Discover the Scope Mask in God's Eye View. Learn about this circular viewport feature that creates a feathered tunnel-vision effect with altitude-adaptive opacity.

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

---

**The Scope Mask is a canvas-based circular viewport that creates a feathered "tunnel-vision" effect, with altitude-adaptive opacity and zero performance cost when disabled.**

The **Scope Mask** is the signature visual feature that gives the open-source geospatial visualization tool **God's Eye View** its distinctive circular focus. Unlike traditional post-processing approaches that rely on shader chains, this feature uses a lightweight 2D canvas layer to deliver GPU-friendly masking with adjustable softness and dynamic transparency. The implementation prioritizes render performance through quantized updates and adaptive repainting.

## How the Scope Mask Works in God's Eye View

The Scope Mask operates as a dedicated `<canvas>` element (`#scope-mask`) positioned beneath detection layers with a z-index of 2. This architectural choice—direct canvas drawing rather than WebGL shaders—eliminates the complexity and overhead of the six post-process shaders that were previously attempted and removed from the codebase.

### Canvas-Based Architecture

The core implementation lives in [`src/scopeMask.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/scopeMask.js) and creates a single persistent canvas attached to the Cesium viewer container. Drawing occurs only when necessary: on initialization, resize, device-pixel-ratio changes, or terminus opacity updates. No per-frame canvas work runs during normal render loops.

Key structural decisions include:

- **Static geometry** — the radial gradient uses pre-computed inner and outer radii from `scopeMaskGeometry(width, height, featherRatio)`
- **Layer separation** — canvas sits at z-index 2, detection layers at z-index 5, ensuring mask appears beneath overlays
- **Clean disable state** — when turned off, the canvas clears once and enters zero-cost idle mode

### Feathered Edge Control

The mask edge uses a **radial gradient** with configurable feathering. The default ratio (`SCOPE_FEATHER_RATIO_DEFAULT = 0.11`) means the soft edge extends 11% of the keyhole radius inward. Users adjust this via the `#scope-feather-slider` control in the UI.

```javascript
// Adjust edge softness from hard crop (0.0) to very soft (0.2)
import { setScopeMaskFeather } from './scopeMask.js';

setScopeMaskFeather(0.15);  // 15% feather radius

```

The `setScopeMaskFeather(ratio)` function triggers a single canvas repaint with the new gradient geometry computed by `scopeMaskGeometry()`.

## Altitude-Adaptive Terminus Opacity

A distinguishing feature of the Scope Mask is its **dynamic opacity response to camera altitude**. The area outside the circular keyhole—called the *terminus*— adjusts transparency based on the viewer's distance from Earth's surface.

### Opacity Thresholds

| Altitude Range | Terminus Behavior | Constant |
|:---|:---|:---|
| Above 10,000 km | Fixed translucent at 94% | `SCOPE_OUTSIDE_ALPHA` |
| Below 7,000 km | Fully opaque at 100% | `SCOPE_TERMINUS_ALPHA_NEAR` |
| 7,000–10,000 km | Smooth-step interpolation | `scopeTerminusAlpha` function |

The smooth-step ramp prevents jarring transitions as users zoom. However, raw continuous updates would waste canvas calls.

### Quantized Repaints for Performance

To minimize canvas operations, terminus opacity changes are **quantized to 0.005 steps** (`SCOPE_TERMINUS_QUANTUM`). A repaint occurs only when the quantized value crosses a grid boundary:

```javascript
// From scopeMask.js - quantized update logic
// Maximum ~12 repaints across full altitude band
const quantized = Math.round(rawAlpha / SCOPE_TERMINUS_QUANTUM) * SCOPE_TERMINUS_QUANTUM;
if (quantized !== lastQuantizedAlpha) {
  requestScopePaint();
}

```

This guarantees bounded canvas work regardless of animation frame rate or zoom velocity.

## Device Pixel Ratio Handling

The implementation correctly handles **high-DPI displays** through a `ResizeObserver` monitoring `window.devicePixelRatio`. When DPR changes:

1. Canvas backing store rescales to new DPR
2. Simultaneous terminus opacity changes coalesce into single paint
3. Gradient regenerated at full native resolution

Only two paint paths exist: DPR-change path (lines 84–94) and quantized-opacity path (lines 92–99), ensuring no redundant operations.

## Public API for the Scope Mask

The [`src/scopeMask.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/scopeMask.js) module exports a clean interface used by [`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js) and other components:

| Function | Purpose | Called From |
|:---|:---|:---|
| `installScopeMask(viewer)` | Initialize canvas in Cesium container | Application bootstrap |
| `setScopeMaskEnabled(enabled)` | Toggle visibility (true/false) | `#scope-toggle` button |
| `setScopeMaskFeather(ratio)` | Update edge softness (0.0–0.2) | `#scope-feather-slider` |
| `setScopeTerminusOverride(alpha)` | Pin opacity, bypass altitude logic | Share-link generation |
| `getScopeTerminusOverride()` | Read current override state | UI state sync |
| `scopeMaskGeometry(w, h, feather)` | Compute gradient radii and center | Internal + external layout |

### Integration with Detection Layers

The mask state propagates to [`src/worldFocus.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/worldFocus.js), which uses the enabled flag to determine whether detection layers should apply clipping. This coordination ensures visual consistency across the rendering pipeline.

## Complete Usage Examples

### Basic Installation and Control

```javascript
// src/main.js or equivalent entry point
import { installScopeMask, setScopeMaskEnabled } from './scopeMask.js';

// After Cesium viewer initialization
installScopeMask(viewer);

// Toggle from UI button handler
document.querySelector('#scope-toggle').addEventListener('click', () => {
  const isEnabled = /* read current state */;
  setScopeMaskEnabled(!isEnabled);
});

```

### Creating Shareable Views with Fixed Opacity

```javascript
import { setScopeTerminusOverride } from './scopeMask.js';

// Lock terminus to 80% opacity for consistent screenshots
setScopeTerminusOverride(0.8);

// Restore altitude-adaptive behavior
setScopeTerminusOverride(null);

```

### Programmatic Feather Adjustment

```javascript
import { setScopeMaskFeather } from './scopeMask.js';

// Animate feather for intro effect
function animateFeather(targetRatio, durationMs) {
  const start = performance.now();
  const initial = 0.05; // Start slightly softer than default
  
  function frame(now) {
    const elapsed = now - start;
    const t = Math.min(elapsed / durationMs, 1);
    const current = initial + (targetRatio - initial) * t;
    
    setScopeMaskFeather(current);
    
    if (t < 1) requestAnimationFrame(frame);
  }
  
  requestAnimationFrame(frame);
}

// Soft edge that tightens to default 0.11
animateFeather(0.11, 800);

```

## Source File Structure

The Scope Mask feature spans four primary files in the `bilawalsidhu/gods-eye-view` repository:

- **[`src/scopeMask.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/scopeMask.js)** — Core implementation with canvas management, gradient drawing, quantized updates, and public API
- **[`src/ui.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/ui.js)** — Button and slider wiring that forwards user input to mask functions
- **[`src/celestialRing.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/celestialRing.js)** — Provides keyhole geometry for mask centering
- **[`src/worldFocus.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/worldFocus.js)** — Consumes mask state for detection layer clipping decisions

## Summary

- The **Scope Mask in God's Eye View** renders a circular viewport using a dedicated 2D canvas, not shader chains, for reliable performance across devices
- **Feathered edges** adjust via `setScopeMaskFeather()` with ratio-based control (default 0.11)
- **Altitude-adaptive terminus opacity** transitions automatically between 94% (high orbit) and 100% (near surface) with smooth-step interpolation
- **Quantized repaints** at 0.005 granularity limit canvas operations to ~12 maximum across all altitudes
- **Zero-cost disable state** clears canvas once, then performs no work until re-enabled
- The public API in [`src/scopeMask.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/scopeMask.js) provides clean integration points for UI controls and programmatic manipulation

## Frequently Asked Questions

### How does the Scope Mask differ from post-processing shader approaches?

The original implementation attempted six chained post-process shaders to create the circular mask, but this produced no actual mask effect and incurred significant GPU overhead. The current canvas-based approach in [`src/scopeMask.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/scopeMask.js) draws a radial gradient directly to a 2D canvas, achieving the visual result with simpler code, better browser compatibility, and explicit control over update frequency.

### What causes the Scope Mask to repaint?

Three events trigger canvas repaints: (1) initialization or resize/device-pixel-ratio changes via `ResizeObserver`, (2) quantized terminus opacity crossing a 0.005 boundary during altitude changes, and (3) explicit calls to `setScopeMaskFeather()` or `setScopeTerminusOverride()`. Normal camera rotation and animation do not trigger repaints.

### Can I use the Scope Mask without the altitude-adaptive opacity?

Yes. Call `setScopeTerminusOverride(alpha)` with any value 0–1 to pin the outer terminus at fixed opacity, bypassing the altitude logic entirely. Pass `null` to restore adaptive behavior. This is useful for creating consistent screenshots, share links, or presentation modes where automatic opacity changes would be distracting.

### Does the Scope Mask impact performance when disabled?

No. When `setScopeMaskEnabled(false)` is called, the canvas clears once to transparent and enters a zero-work state. No canvas operations, no gradient calculations, and no resize observations occur until the mask is re-enabled. The "scope off" configuration is explicitly designed as the cheapest possible rendering path.