constructor(layer, options) {
    super(layer, {
      vertexShader: options.tileVertexShader,
      fragmentShader: options.tileFragmentShader,
      cacheSize: options.cacheSize,
      // TODO: rework the post-processing logic
      // see https://github.com/openlayers/openlayers/issues/16120
      postProcesses: [{}],
      uniforms: {
        [U.MAX_SPEED]: options.maxSpeed,
      },
    });

    /**
     * @type {string}
     * @private
     */
    this.particleColorFragmentShader_ = options.particleColorFragmentShader;

    /**
     * @type {WebGLTexture|null}
     * @private
     */
    this.velocityTexture_ = null;

    /**
     * @type {number}
     * @private
     */
    this.particleCountSqrt_ = options.particles
      ? Math.ceil(Math.sqrt(options.particles))
      : 256;

    /**
     * @type {WebGLArrayBuffer}
     * @private
     */
    this.particleIndexBuffer_;

    /**
     * @type {WebGLArrayBuffer}
     * @private
     */
    this.quadBuffer_;

    /**
     * @type {WebGLProgram}
     * @private
     */
    this.particlePositionProgram_;

    /**
     * @type {string}
     * @private
     */
    this.particlePositionVertexShader_ = options.particlePositionVertexShader;

    /**
     * @type {string}
     * @private
     */
    this.particlePositionFragmentShader_ =
      options.particlePositionFragmentShader;

    /**
     * @type {WebGLTexture}
     * @private
     */
    this.previousPositionTexture_;

    /**
     * @type {WebGLTexture}
     * @private
     */
    this.nextPositionTexture_;

    /**
     * @type {WebGLProgram}
     * @private
     */
    this.particleColorProgram_;

    /**
     * @type {string}
     * @private
     */
    this.particleColorVertexShader_ = options.particleColorVertexShader;

    /**
     * @type {string}
     * @private
     */
    this.particleColorFragmentShader_ = options.particleColorFragmentShader;

    /**
     * @type {WebGLProgram}
     * @private
     */
    this.textureProgram_;

    /**
     * @type {string}
     * @private
     */
    this.textureVertexShader_ = options.textureVertexShader;

    /**
     * @type {string}
     * @private
     */
    this.textureFragmentShader_ = options.textureFragmentShader;

    /**
     * @type {WebGLTexture}
     * @private
     */
    this.previousTrailsTexture_;

    /**
     * @type {WebGLTexture}
     * @private
     */
    this.nextTrailsTexture_;

    /**
     * @type {number}
     * @private
     */
    this.fadeOpacity_ = 0.996; // how fast the particle trails fade on each frame

    /**
     * @type {number}
     * @private
     */
    this.maxSpeed_ = options.maxSpeed;

    /**
     * @type {number}
     * @private
     */
    this.speedFactor_ = options.speedFactor || 0.001;

    /**
     * @type {number}
     * @private
     */
    this.dropRate_ = 0.003; // how often the particles move to a random place

    /**
     * @type {number}
     * @private
     */
    this.dropRateBump_ = 0.01; // drop rate increase relative to individual particle speed

    /**
     * @type {Array<number>}
     * @private
     */
    this.tempVec2_ = [0, 0];

    /**
     * @type {number}
     * @private
     */
    this.renderedWidth_ = 0;

    /**
     * @type {number}
     * @private
     */
    this.renderedHeight_ = 0;
  }
@param {LayerType} layer The tiled field layer.
@param {Options} options The renderer options.