startDynamicWatermark_(config) {
    const ctx = /** @type {!CanvasRenderingContext2D} */ (
      this.canvas_.getContext('2d')
    );
    let currentPosition = {left: 0, top: 0};
    let currentAlpha = 0;
    let phase = 'fadeIn'; // States: fadeIn, display, fadeOut, transition

    let displayFrames = Math.round(config.displayDuration * 60); // 60fps
    const transitionFrames = Math.round(config.transitionDuration * 60);
    const fadeSpeed = 1 / (transitionFrames / 2); // Smoother fade speed

    /** @private {number} */
    let positionIndex = 0;

    const getNextPosition = () => {
      ctx.font = `${config.size}px Arial`;
      const textMetrics = ctx.measureText(config.text);
      const textWidth = textMetrics.width;
      const textHeight = config.size;
      const padding = 20;

      // Define fixed positions
      const positions = [
        // Top-left
        {
          left: padding,
          top: textHeight + padding,
        },
        // Top-right
        {
          left: this.canvas_.width - textWidth - padding,
          top: textHeight + padding,
        },
        // Bottom-left
        {
          left: padding,
          top: this.canvas_.height - padding,
        },
        // Bottom-right
        {
          left: this.canvas_.width - textWidth - padding,
          top: this.canvas_.height - padding,
        },
        // Center
        {
          left: (this.canvas_.width - textWidth) / 2,
          top: (this.canvas_.height + textHeight) / 2,
        },
      ];

      // Cycle through positions
      const position = positions[positionIndex];
      positionIndex = (positionIndex + 1) % positions.length;
      return position;
    };

    currentPosition = getNextPosition();

    const updateWatermark = () => {
      if (!this.animationId_) {
        return;
      }

      const width = this.canvas_.width;
      const height = this.canvas_.height;
      ctx.clearRect(0, 0, width, height);

      // State machine for watermark phases
      switch (phase) {
        case 'fadeIn':
          currentAlpha = Math.min(config.alpha, currentAlpha + fadeSpeed);
          if (currentAlpha >= config.alpha) {
            phase = 'display';
          }
          break;
        case 'display':
          if (--displayFrames <= 0) {
            phase = 'fadeOut';
          }
          break;
        case 'fadeOut':
          currentAlpha = Math.max(0, currentAlpha - fadeSpeed);
          if (currentAlpha <= 0) {
            phase = 'transition';
            currentPosition = getNextPosition();
            displayFrames = Math.round(config.displayDuration * 60);
            phase = 'fadeIn';
          }
          break;
      }

      // Draw watermark if visible
      if (currentAlpha > 0) {
        ctx.globalAlpha = currentAlpha;
        ctx.fillStyle = config.color;
        ctx.font = `${config.size}px Arial`;
        ctx.fillText(config.text, currentPosition.left, currentPosition.top);
      }

      // Request next frame if animation is still active
      if (this.animationId_) {
        this.animationId_ = requestAnimationFrame(updateWatermark);
      }
    };

    // Start the animation loop
    this.animationId_ = requestAnimationFrame(updateWatermark);
  }
Starts a dynamic watermark animation on the canvas.
@param {!shaka.ui.Watermark.Options} config  configuration options
@private