Создай интерактивный блок X-ray reveal: при движении курсора мягкое круглое окно в верхней фотографии открывает нижнюю. Без увеличения изображения, заголовков, текста, кнопок и автопрокрутки.
Весь контент должен легко редактироваться в Тильде: обе фотографии сразу пропиши отдельными img в HTML с data-tilda-img="y". Не создавай контент через JS, массивы, innerHTML или canvas. JS управляет только эффектом через CSS-переменные. В редакторе отключи анимацию и покажи оба исходных фото доступными для выбора и замены, без перехвата кликов. На опубликованной странице наложи их друг на друга.
Нижнее фото, открываемое внутри окна:
https://static.tildacdn.com/tild6362-6565-4561-b234-643363396136/Group_2136139225.jpg
Верхнее фото, видимое в покое:
https://static.tildacdn.com/tild3930-6636-4139-b861-326439333564/1_12.jpg
Белая секция width:100%, padding:72px 20px. По центру кадр width:min(92vw,1180px), aspect-ratio:16/10, radius:4px, overflow:hidden, фон #f2f2f2, isolation:isolate. Оба img занимают кадр целиком: position:absolute; inset:0; width/height:100%; object-fit:cover; object-position:center; draggable:false. Нижнее z-index:1, обёртка верхнего z-index:2, контур окна z-index:3.
В покое радиус r=0, видна только верхняя фотография. При входе мыши в кадр сразу поставь центр окна в точку входа, затем плавно увеличь r до 150px. При движении центр следует за указателем с инерцией; при выходе r плавно уменьшается до 0. Обычный курсор внутри кадра скрыт.
Прозрачное отверстие сделай CSS mask-image и -webkit-mask-image на обёртке верхнего img: radial-gradient(ellipse calc(r*sx*2) calc(r*sy*2) at x y, transparent 0%, transparent 54%, rgba(0,0,0,.25) 74%, #000 100%). Центр полностью раскрывает нижнее фото, края мягко смешивают снимки. Не используй жёсткую круговую обрезку. Поверх — тонкое кольцо размером 2r×2r, border:1px solid rgba(255,255,255,.72), radius:50%, тень 0 0 0 1px rgba(0,0,0,.10), pointer-events:none; центр совпадает с окном.
Анимация через requestAnimationFrame: lerp позиции .20, радиуса .13; поправка на время кадра factor=1-(1-alpha)^(delta/16.67), delta≤100ms. Лёгкая упругость: speed=hypot(dx,dy)/delta, stretchTarget=clamp(speed*.004,0,.42), сглаживание .20; sx=1+stretch, sy=1-stretch*.42. Кольцо translate(-50%,-50%) rotate(angle) scaleX(sx) scaleY(sy); angle=atan2(dy,dx) при speed>.35. Маска использует sx/sy без вращения.
768–1199px: padding:56px 16px, кадр 3:2. ≤767px: padding:32px 14px, width:calc(100vw - 28px), кадр 4:5, обычный курсор. На touch окно открывается под пальцем до r=132px, следует за касанием и закрывается при отпускании/cancel. Координаты ограничь кадром; passive-обработчики не блокируют прокрутку страницы.
Изолируй CSS/JS, поддержи несколько экземпляров без повторной инициализации. ResizeObserver пересчитывает размер, вне экрана и в скрытой вкладке rAF остановлен. При reduced-motion отключи эффект и кольцо, покажи верхнее фото с обычным курсором.