This example uses OpenLayers v10.9.0. The latest is v.
Edit

#### Equal Earth projection with dynamic center meridian

vector 86 geojson 11 equal-earth 1

#####

Example of a vector layer in Equal Earth projection with dynamic center meridian.

The countries are loaded from a GeoJSON file. Information about countries is shown on hover and click.

##### main.js

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import GeoJSON from 'ol/format/GeoJSON.js';
    import VectorLayer from 'ol/layer/Vector.js';
    import {fromLonLat, get as getProjection, toLonLat} from 'ol/proj.js';
    import {register} from 'ol/proj/proj4.js';
    import RenderFeature from 'ol/render/Feature.js';
    import VectorSource from 'ol/source/Vector.js';
    import proj4 from 'proj4';

    // Equal Earth projection with dynamic center meridian
    function dynEqualEarth(center, round = 15) {
      const lon0 = Math.round(center[0] / round) * round;
      const code = `EqualEarth${lon0}`;
      let prj = getProjection(code);
      if (!prj) {
        proj4.defs(
          code,
          `+proj=eqearth +lon_0=${lon0} +x_0=0 +y_0=0 +R=6371008.7714 +units=m +no_defs +type=crs`,
        );
        register(proj4);
        prj = getProjection(code);
        prj.setGlobal(true);
        prj.setExtent([-17243959.06, -8392927.6, 17243959.06, 8392927.6]);
        prj.setWorldExtent([-180, -90, 180, 90]);
      }

      return prj;
    }

    const initialCenter = [11, 0];
    const initialProjection = dynEqualEarth(initialCenter, 1);

    (async () => {
      const response = await fetch(
        'https://openlayers.org/data/vector/ecoregions.json',
        // 'https://openlayersbook.github.io/openlayers_book_samples/assets/data/countries.geojson',
      );
      const geojson = await response.json();

      function jsonSource(geojson, projection) {
        return new VectorSource({
          features: new GeoJSON({
            featureProjection: projection,
            featureClass: RenderFeature,
          }).readFeatures(geojson),
          overlaps: false,
        });
      }

      const vectorLayer = new VectorLayer({
        source: jsonSource(
          clipPolygon(geojson, initialCenter[0]),
          initialProjection,
        ),
        extent: initialProjection.getExtent(),
        wrapX: false,
        style: {
          'fill-color': ['string', ['get', 'COLOR'], '#eee'],
        },
      });

      const map = new Map({
        layers: [vectorLayer],
        target: 'map',
        view: new View({
          projection: initialProjection,
          center: initialCenter,
          zoom: 0,
          showFullExtent: true,
        }),
      });

      // Event handler for updating view projection
      function handleCenterChange() {
        const degStep = 5;
        const curView = map.getView();
        const center = toLonLat(curView.getCenter(), curView.getProjection());
        const newProjection = dynEqualEarth(center, degStep);
        if (curView.getProjection().getCode() !== newProjection.getCode()) {
          curView.un('change:center', handleCenterChange);
          const lon0 = Math.round(center[0] / degStep) * degStep;
          // Clip polygons at the new antimeridian to avoid rendering artifacts
          const clippedJson = clipPolygon(geojson, lon0);
          // Reload source to apply the new projection
          vectorLayer.setSource(jsonSource(clippedJson, newProjection));
          map.setView(
            new View({
              projection: newProjection,
              center: fromLonLat(center, newProjection),
              zoom: curView.getZoom(),
              rotation: curView.getRotation(),
              showFullExtent: true,
            }),
          );
          map.getView().on('change:center', handleCenterChange);
        }
      }

      map.getView().on('change:center', handleCenterChange);

      function clipPolygon(geojson, lon0) {
        function roundN(num, n = 10) {
          return Math.round(num * Math.pow(10, n)) / Math.pow(10, n);
        }
        const minX = lon0 - 180.0;
        const maxX = lon0 + 180.0;
        const clippedJson = {type: 'FeatureCollection', features: []};
        for (const feature of geojson.features) {
          const depth = feature.geometry.type === 'MultiPolygon' ? 2 : 1;
          const [featMinX, featMaxX] = feature.geometry.coordinates
            .flat(depth)
            .reduce(
              (minmax, coord) => [
                Math.min(minmax[0], coord[0]),
                Math.max(minmax[1], coord[0]),
              ],
              [Number.MAX_VALUE, Number.MIN_VALUE],
            );
          const eps = 0.01;
          if (
            (featMinX < minX + eps && featMaxX > minX - eps) ||
            (featMinX < maxX + eps && featMaxX > maxX - eps)
          ) {
            const offset = featMinX < minX ? 360 : -360;
            const feat = structuredClone(feature);
            if (feat.geometry.type === 'Polygon') {
              feat.geometry.type = 'MultiPolygon';
              feat.geometry.coordinates = [feat.geometry.coordinates];
            }

            const polys = [];
            for (const polygon of feat.geometry.coordinates) {
              const tpoly = structuredClone(polygon);
              const ncoords = polygon.reduce((sum, ring) => sum + ring.length, 0);
              let clamped = 0;
              for (const ring of polygon) {
                for (const coord of ring) {
                  const x = coord[0];
                  coord[0] = roundN(Math.min(Math.max(x, minX), maxX));
                  if (coord[0] !== roundN(x)) {
                    clamped++;
                  }
                }
              }
              // Skip possibly degenerated polys with all coords clamped
              if (clamped < ncoords) {
                polys.push(polygon);
              }
              // Shift poly by 360° and clamp other part
              if (clamped) {
                let around180 = false;
                for (const ring of tpoly) {
                  for (const coord of ring) {
                    const x = coord[0] + offset;
                    coord[0] = Math.min(Math.max(x, minX + eps), maxX - eps);
                    // this still creates bad polys when coords are around 180°
                    if (Math.abs(coord[0]) - 180 < 0.00000001) {
                      around180 = true;
                    }
                  }
                }
                if (!around180) {
                  polys.push(tpoly);
                }
              }
            }
            feat.geometry.coordinates = polys;
            clippedJson.features.push(feat);
          } else {
            clippedJson.features.push(feature);
          }
        }
        return clippedJson;
      }

      const featureOverlay = new VectorLayer({
        source: new VectorSource(),
        map: map,
        style: {
          'stroke-color': 'rgba(255, 255, 255, 0.7)',
          'stroke-width': 2,
        },
      });

      let highlight;
      const displayFeatureInfo = function (pixel) {
        const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
          return feature;
        });

        const info = document.getElementById('info');
        if (feature) {
          info.innerHTML =
            feature.get('ECO_NAME') || feature.get('name') || '&nbsp;';
        } else {
          info.innerHTML = '&nbsp;';
        }

        if (feature !== highlight) {
          if (highlight) {
            featureOverlay.getSource().removeFeature(highlight);
          }
          if (feature) {
            featureOverlay.getSource().addFeature(feature);
          }
          highlight = feature;
        }
      };

      map.on('pointermove', function (evt) {
        if (evt.dragging) {
          return;
        }
        displayFeatureInfo(evt.pixel);
      });

      map.on('click', function (evt) {
        displayFeatureInfo(evt.pixel);
      });
    })();

##### index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Equal Earth projection with dynamic center meridian</title>
        <link rel="stylesheet" href="node_modules/ol/ol.css">
        <style>
          .map {
            width: 100%;
            height: 400px;
          }
        </style>
      </head>
      <body>
        <div id="map" class="map"></div>
        <div id="info">&nbsp;</div>

        <script type="module" src="main.js"></script>
      </body>
    </html>

##### package.json

    {
      "name": "equal-earth-geojson",
      "dependencies": {
        "ol": "10.9.0",
        "proj4": "2.20.8"
      },
      "devDependencies": {
        "vite": "^3.2.3"
      },
      "scripts": {
        "start": "vite",
        "build": "vite build"
      }
    }