rebuildBuffers_(frameState) {
    // saves the projection transform for the current frame state
    const projectionTransform = createTransform();
    this.helper.makeProjectionTransform(frameState, projectionTransform);

    const userProjection = getUserProjection();

    const baseInstructionLength = this.hitDetectionEnabled_ ? 7 : 2; // see below
    const singleInstructionLength =
      baseInstructionLength + this.customAttributes.length;
    const totalSize = singleInstructionLength * this.featureCount_;
    const renderInstructions =
      this.renderInstructions_ && this.renderInstructions_.length === totalSize
        ? this.renderInstructions_
        : new Float32Array(totalSize);
    this.renderInstructions_ = null;

    // loop over features to fill the buffer
    /** @type {import('../../coordinate.js').Coordinate} */
    let tmpCoords = [];
    /** @type {Array<number>} */
    const tmpColor = [];
    let idx = -1;
    const projection = frameState.viewState.projection;
    for (const featureUid in this.featureCache_) {
      const featureCache = this.featureCache_[featureUid];
      if (userProjection) {
        tmpCoords = fromUserCoordinate(
          featureCache.flatCoordinates,
          projection,
        );
      } else {
        tmpCoords[0] = featureCache.flatCoordinates[0];
        tmpCoords[1] = featureCache.flatCoordinates[1];
      }
      applyTransform(projectionTransform, tmpCoords);

      renderInstructions[++idx] = tmpCoords[0];
      renderInstructions[++idx] = tmpCoords[1];

      // for hit detection, the feature uid is saved in the opacity value
      // and the index of the opacity value is encoded in the color values
      if (this.hitDetectionEnabled_) {
        const hitColor = colorEncodeId(idx + 5, tmpColor);
        renderInstructions[++idx] = hitColor[0];
        renderInstructions[++idx] = hitColor[1];
        renderInstructions[++idx] = hitColor[2];
        renderInstructions[++idx] = hitColor[3];
        renderInstructions[++idx] = Number(featureUid);
      }

      // pushing custom attributes
      for (let j = 0; j < this.customAttributes.length; j++) {
        const value = this.customAttributes[j].callback(
          featureCache.feature,
          featureCache.properties,
        );
        renderInstructions[++idx] = value;
      }
    }

    /** @type {import('../../render/webgl/constants.js').WebGLWorkerGenerateBuffersMessage} */
    const message = {
      id: ++this.lastSentId,
      type: WebGLWorkerMessageType.GENERATE_POINT_BUFFERS,
      renderInstructions: renderInstructions.buffer,
      customAttributesSize: singleInstructionLength - 2,
    };
    // additional properties will be sent back as-is by the worker
    message['projectionTransform'] = projectionTransform;
    this.ready = false;
    this.worker_.postMessage(message, [renderInstructions.buffer]);
  }
Rebuild internal webgl buffers based on current view extent; costly, should not be called too much
@param {import("../../Map").FrameState} frameState Frame state.
@private