What this app is

Half-Earth v3 is a Vite + React single-page application that renders a 3D ArcGIS SceneView β€œglobe” alongside data-driven scenes and UIs. Redux powers routing and synchronizes UI/globe state into the URL, enabling shareable, reproducible views. Translations, analytics, and content integrations complete the platform.

Key technologies

  • React 17, Redux, redux-first-router
  • @arcgis/core 4.x (ArcGIS JS API) for the 3D globe
  • @loadable/component for page-level code-splitting
  • @tanstack/react-query for server-state
  • Transifex Native for i18n
  • SCSS modules for styles

Entry points

  • index.html: loads ArcGIS CSS and bootstraps the app bundle
  • src/index.jsx: creates the Redux store and mounts
  • src/app.jsx: initializes Transifex + React Query and lazy-loads pages based on the current route

Code organization (where things live)

  • Pages (src/pages/*)
    • Top-level routes: data-globe, featured-globe, aoi, nrc (+ mobile variants under src/pages/mobile/*).
    • Pages compose a scene with page chrome (headers, sidebars, modals, menus).
  • Scenes (src/containers/scenes/*)
    • Each scene wraps the ArcGIS SceneView via components/scene and owns per-scene configuration (sceneSettings).
    • Orchestrates layers, sidebars, tooltips, onboarding, and other managers.
  • Components (src/components/*)
    • Reusable presentational components. Notable: components/scene/* (Scene wrapper), tooltips, modals.
  • Containers (src/containers/*)
    • β€œSmart” components wired to Redux and ArcGIS.
    • Includes layers/, sidebars/, menus/, and managers/ (arcgis-layer-manager, globe-events-manager, zoom-into-geometry-manager, etc.).
  • Store (src/store/*)
    • store/store.ts and store/reducerRegistry.js implement the Redux store and dynamic reducer injection.
    • store/redux-modules/* contains feature modules (actions, reducers, initial state) registered on demand.
  • Constants (src/constants/*)
    • Layer and scene configuration, slugs, and service URLs (e.g., mol-layers-configs, layers-urls, layers-groups, layers-slugs).
  • Utils, hooks, services
    • src/utils/*: ArcGIS helpers (layer creation/visibility/order, globe events, state-to-url) and general utilities.
    • src/hooks/*: custom hooks (e.g., hooks/esri.js for search/sketch widgets and watch utils).
    • src/services/*: service wrappers (e.g., esri-feature-service.ts for querying/editing FeatureLayers).
  • Styles (src/styles/*)
    • SCSS modules and theme styles (e.g., styles/themes/scene-theme.module.scss).

Routing and URL-state model

Router

  • redux-first-router connectRoutes is configured in src/router.ts.
  • Each route defines a path and a page key used by App to lazy-load the right page.

URL serialization

  • src/utils/state-to-url encodes/decodes JSON-like state into location.query.
  • Main query keys:
    • globe: camera center/zoom, activeLayers, basemap, labels, terrain, and globe UI toggles.
    • ui: non-globe UI state (sidebars, modals, menus, onboarding, etc.).
    • lang: current locale.

Actions

  • store/actions/url-actions exposes changeGlobe, changeUI, changeLang.
  • Each action updates only its subtree in location.query, preserving the rest.

State management (high level)

  • The Redux store (store/store.ts) composes base reducers and supports dynamic reducer registration through store/reducerRegistry.js.
  • Feature modules under store/redux-modules/ export a reduxConfig that reducerRegistry.registerModule consumes to inject reducers at runtime (code-splitting friendly).
  • Location (redux-first-router) provides routing and the URL-backed state used by selectors.
  • Deep dive: State Management β†’ /_docs/dev/architecture/state-management

The ArcGIS β€œglobe” architecture

Scene wrapper

  • components/scene/scene.js + scene-component.jsx create an ArcGIS Map and a 3D SceneView for each scene.
  • Applies per-scene settings (environment, constraints, padding, popup UI) via the sceneSettings prop.
  • On mobile, the Scene uses a lower qualityProfile to reduce GPU load.

Camera, rotation, and URL sync

  • Optional initial rotation animates the globe on first visit; a flag in localStorage avoids repeating.
  • Uses @arcgis/core/core/reactiveUtils (via hooks/esri) to update the URL when the view becomes stationary (center + zoom).

Touch pan refinement

  • A custom touch-pan handler in the Scene improves iOS Safari behavior for one-finger panning.

Basemap handling

  • utils/layer-manager-utils.setBasemap composes a Basemap from configured base layers (constants/mol-layers-configs + constants/layers-urls).

Layer system overview

  • Configuration-driven: constants/mol-layers-configs maps slugs β†’ type (FeatureLayer, TileLayer, VectorTileLayer), URL or portalId, default opacity, optional renderer and bbox.
  • Creation/activation: utils/layer-manager-utils.createLayer/addLayerToMap/activateLayersOnLoad and addActiveLayersToScene instantiate and add activeLayers from state.
  • Visibility/order/opacity: containers/managers/arcgis-layer-manager calls utils/arcgis-layer-manager-utils.setLayersVisibility (and optionally setLayersOrder) based on activeLayers.
  • Labels: containers/layers/labels-layer styles label layers with LabelClass rules from @arcgis/core.

Events and interactions

  • containers/managers/globe-events-manager attaches pointer handlers and uses view.hitTest; utils/globe-events-utils centralizes hit results, cursor updates, flyTo helpers, and avatar/marker placement.
  • hooks/esri.js exposes search and sketch widget logic, including area validation against configured limits.

Examples by scene

  • Data scene (src/containers/scenes/data-scene/*): thematic layers, labels, tooltips, sidebars, and the globes menu. Configured via data-scene-config.js.
  • AOI scene (src/containers/scenes/aoi-scene/*): AOI mask/outline, optional terrain exaggeration, basemap selector, and ZoomIntoGeometryManager for camera transitions.

Per-scene layer configuration files

  • Each scene ships with a dedicated config module that defines its initial globe and UI state, especially the list/order of layers.
  • Examples:
    • src/containers/scenes/data-scene/data-scene-config.js defines globe.activeLayers, zoom/center, padding, environment, popup and basemap.
    • src/containers/scenes/aoi-scene/config.js defines activeLayers, padding, environment, constraints and basemap.
  • How it flows: 1) The page builds sceneSettings from the scene’s config and passes it to the Scene component (components/scene). 2) On map load, activateLayersOnLoad(map, initialActiveLayers, layersConfig) instantiates those layers by looking up their slug in constants/mol-layers-configs. 3) ArcgisLayerManager keeps visibility/opacity in sync with activeLayers changes.
  • This separation lets us evolve per‑scene defaults without touching the global layer registry (constants/mol-layers-configs, constants/layers-urls).

Data and services

  • ArcGIS Online: constants/layers-urls centralize FeatureServer/MapServer URLs and portal item ids per layer slug.
  • Service helpers: src/services/esri-feature-service.ts wraps querying/editing via @arcgis/core and @esri/arcgis-rest-feature-layer.

Contentful content and translations

  • What we store there
    • Layer metadata (descriptions, sources, credits) used across the UI.
    • Featured maps stories (editorial content) shown in the Featured Globe and related views.
  • Per-locale pages in Contentful
    • Content entries are translated per locale in Contentful (separate localized pages/entries).
    • The app requests the appropriate locale when fetching entries so users see the correct language.
  • Where the locale comes from
    • We keep the UI locale in the URL (location.query.lang) and initialize Transifex in src/app.jsx.
    • The same locale value is used when requesting Contentful entries.
  • More details
    • Translation docs: /_docs/dev/translation
    • Contentful metadata: /_docs/scientists/metadata-contentful

Performance and code-splitting

  • Pages are lazy-loaded with @loadable/component to keep the initial bundle small.
  • Redux reducers load on demand via reducerRegistry; avoid upfront loading of all modules.
  • ArcGIS CSS is linked in index.html; ArcGIS API resources are lazily used by the Scene.
  • Prefer reusing created layers; avoid unnecessary re-instantiation when toggling visibility/opacity.

How to extend

Add or update layers

  • Follow the guide: /_docs/dev/layers/add-update
  • Typical steps: add/update constants/mol-layers-configs and constants/layers-urls entries; ensure the visibility/ordering path in arcgis-layer-manager is correct; test URL serialization for activeLayers.

Add a new scene/page

  • Add a route in src/router.ts (path + page key).
  • Create a page under src/pages/ and wire it in App (lazy-loaded with @loadable/component).
  • Compose a scene in src/containers/scenes/ with components/scene; define sceneSettings and required managers (layer, events, zoom).
  • If the new state is URL-driven, add actions/selectors and update constants as needed; consider onboarding and mobile variants.
  • State management: /_docs/dev/architecture/state-management
  • Working with layers (add/update): /_docs/dev/layers/add-update
  • Components catalog: /_docs/dev/components
  • Translation: /_docs/dev/translation
  • Developer index and environment: /_docs/dev

Table of contents