Кастомный курсор

Нужно нарисовать блок и за мышкой его двигать. Чтобы при появлении и исчезновении он не прыгал относительно курсора, нужно самому блоку — курсору задать смещение.

В этом примере я сделал через отрицательый margin. При наведении на блок, где должен менять курсор — срабатывает плавное появление из центра кргуляшка ровно где курсор.

class Cursor {
    constructor(options = {}) {
        this.containerClass = '.j-cursor-container';
        this.cursorClass = '.j-cursor';

        this.cursor = document.querySelector(this.cursorClass);
        this.container =  document.querySelector(this.containerClass);
    }

    init() {
        this._createCursor();

        if (window.innerWidth > 1200) {
            this._moveCursor();
        }
    }

    _moveCursor() {
        const cursor = this.cursor;

        if (!cursor) {
            this._createCursor();
        }

        document.addEventListener('mousemove',  (event) => {
            if (event.target.closest('.j-cursor-container') && !event.target.classList.contains('j-no-cursor')) {

                this._showCursor();

                this.cursor.innerHTML = event.target.closest('.j-cursor-container').dataset.title || '';

                const contRect = document.body.getBoundingClientRect();
                const cursRect = cursor.getBoundingClientRect();

                let cursX = event.clientX - contRect.left - cursRect.width / 2;
                const cursY = event.clientY - contRect.top - cursRect.height / 2;

                cursor.style.top = `${cursY}px`;
                cursor.style.left = `${cursX}px`;

            }
            else {
                this._hideCursor();
            }
        }, {passive: true});
    }

    _createCursor() {
        const cursor = this.cursor;
        if (!cursor) {
            document.body.insertAdjacentHTML('beforeend', '<div class="cursor j-cursor"></div>');
        }
    }

    _showCursor () {
        this.cursor.classList.remove('cursor-hide');

    }

    _hideCursor () {
        this.cursor.classList.add('cursor-hide');
    }
}

export default Cursor;
.cursor {
  display: none;

  @media  #{$desktop} {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 200px;
    height: 200px;
    border-radius: 50%;
    box-shadow: 0 0 16px 0 rgba(255, 255, 255, 0.25) inset;
    background-color: rgba(28, 29, 57, 0.5);
    backdrop-filter: blur(5px);
    --o-filter: blur(5px);
    position: absolute;
    z-index: 6;
    pointer-events: none;
    @include contentSmallTitleFont();
    text-align: center;
    transition: 0.1s ease-in-out;
    transition-property: transform;
    transform-origin: center center;
    margin-top: -100px;
    margin-left: -100px;
  }

  @media #{$ultra} {
    width: 240px;
    height: 240px;
    margin-top: -120px;
    margin-left: -120px;
  }

  &-hide {
    transform: scale(0);

  }

  &-container {
    @media  #{$desktop} {
      @media (hover) {
        cursor: none !important;
      }
    }
  }
}