diff --git a/assets/custom/js/interaction-overrides.js b/assets/custom/js/interaction-overrides.js
index 857403b..f75baf7 100644
--- a/assets/custom/js/interaction-overrides.js
+++ b/assets/custom/js/interaction-overrides.js
@@ -12,8 +12,15 @@
const MEDIA_HANDLE_BOUND_FLAG = "__nodedcMediaHandleBound";
const DOCK_LINK_BOUND_FLAG = "__nodedcDockLinkBound";
const ORDERED_SLIDER_BOUND_FLAG = "__nodedcOrderedSliderBound";
+ const SCROLL_HEIGHT_SYNC_FLAG = "__nodedcScrollHeightSyncBound";
+ const SCROLL_HEIGHT_SYNC_WARMUP_MS = 14000;
+ const SCROLL_HEIGHT_SYNC_INTERVAL_MS = 90;
const IMAGE_EXTENSIONS = new Set(["avif", "gif", "jpeg", "jpg", "png", "svg", "webp"]);
const VIDEO_EXTENSIONS = new Set(["m4v", "mov", "mp4", "webm"]);
+ let lastDocumentScrollHeight = 0;
+ let scrollHeightSyncFrame = 0;
+ let scrollHeightSyncShouldForce = false;
+ let scrollHeightDeferredSync = 0;
function isDesktopPointer() {
return window.matchMedia?.("(pointer: fine)").matches ?? true;
@@ -55,6 +62,99 @@
return Math.min(max, Math.max(min, value));
}
+ function getDocumentScrollHeight() {
+ return Math.max(document.documentElement.scrollHeight, document.body?.scrollHeight || 0);
+ }
+
+ function notifyScrollHeightChange(force = false) {
+ const nextHeight = getDocumentScrollHeight();
+ if (!nextHeight) return;
+ if (!force && nextHeight === lastDocumentScrollHeight) return;
+
+ lastDocumentScrollHeight = nextHeight;
+ window.dispatchEvent(new Event("resize"));
+
+ if (scrollHeightDeferredSync) {
+ window.clearTimeout(scrollHeightDeferredSync);
+ }
+
+ scrollHeightDeferredSync = window.setTimeout(() => {
+ scrollHeightDeferredSync = 0;
+ if (getDocumentScrollHeight() === lastDocumentScrollHeight) {
+ window.dispatchEvent(new Event("resize"));
+ } else {
+ scheduleScrollHeightSync();
+ }
+ }, 320);
+ }
+
+ function scheduleScrollHeightSync(force = false) {
+ scrollHeightSyncShouldForce = scrollHeightSyncShouldForce || force;
+ if (scrollHeightSyncFrame) return;
+
+ scrollHeightSyncFrame = window.requestAnimationFrame(() => {
+ const shouldForce = scrollHeightSyncShouldForce;
+
+ scrollHeightSyncShouldForce = false;
+ scrollHeightSyncFrame = 0;
+ notifyScrollHeightChange(shouldForce);
+ });
+ }
+
+ function bindScrollHeightSync() {
+ if (document[SCROLL_HEIGHT_SYNC_FLAG]) return;
+ document[SCROLL_HEIGHT_SYNC_FLAG] = true;
+
+ scheduleScrollHeightSync(true);
+
+ const resizeObserver =
+ typeof ResizeObserver === "function"
+ ? new ResizeObserver(() => {
+ scheduleScrollHeightSync();
+ })
+ : null;
+
+ resizeObserver?.observe(document.documentElement);
+ if (document.body) resizeObserver?.observe(document.body);
+
+ const mutationObserver =
+ typeof MutationObserver === "function"
+ ? new MutationObserver(() => {
+ scheduleScrollHeightSync();
+ })
+ : null;
+
+ mutationObserver?.observe(document.documentElement, {
+ attributes: true,
+ childList: true,
+ subtree: true,
+ });
+
+ const interval = window.setInterval(() => {
+ scheduleScrollHeightSync();
+ }, SCROLL_HEIGHT_SYNC_INTERVAL_MS);
+
+ window.setTimeout(() => {
+ window.clearInterval(interval);
+ mutationObserver?.disconnect();
+ }, SCROLL_HEIGHT_SYNC_WARMUP_MS);
+
+ window.addEventListener("load", () => scheduleScrollHeightSync(true), { once: true });
+ if (document.fonts?.ready) {
+ document.fonts.ready.then(() => scheduleScrollHeightSync(true)).catch(() => {});
+ }
+
+ document.addEventListener(
+ "load",
+ (event) => {
+ if (event.target instanceof HTMLImageElement || event.target instanceof HTMLVideoElement) {
+ scheduleScrollHeightSync();
+ }
+ },
+ true,
+ );
+ }
+
function getScrollSpeed(surface) {
const rawValue = surface?.dataset?.scrollSpeed ?? surface?.closest?.("[data-scroll-speed]")?.dataset?.scrollSpeed;
const value = Number.parseFloat(rawValue);
@@ -358,40 +458,48 @@
document.querySelectorAll("[data-adaptive-video] video").forEach(bindAdaptiveVideo);
}
+ bindScrollHeightSync();
hydrateMediaHandles();
if (document.readyState === "loading") {
document.addEventListener(
"DOMContentLoaded",
() => {
+ bindScrollHeightSync();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
bindDockLinks();
bindAdaptiveVideos();
+ scheduleScrollHeightSync(true);
},
{ once: true },
);
} else {
+ bindScrollHeightSync();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
bindDockLinks();
bindAdaptiveVideos();
+ scheduleScrollHeightSync(true);
}
window.addEventListener("load", () => {
+ bindScrollHeightSync();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
bindDockLinks();
bindAdaptiveVideos();
+ scheduleScrollHeightSync(true);
window.setTimeout(() => {
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
bindDockLinks();
bindAdaptiveVideos();
+ scheduleScrollHeightSync(true);
}, 500);
});
})();
diff --git a/index.html b/index.html
index 780c240..35c1cdb 100644
--- a/index.html
+++ b/index.html
@@ -490,4 +490,4 @@ Enterprise-контуры
Подключить.Собрать контур. Запустить.
Платформа NODE.DC для процессов, данных и агентов.
включённым объёмом в каждом тарифе.












Единая точка входа: каталог приложений, рабочие пространства, роли, группы и права доступа.

Нодовые workflow, обработчики данных, интеграционная логика и сборка прикладных контуров.

Операционные карточки, статусы, согласования, отчеты агентов и результаты выполнения задач.

Связка с 1C, разбор документов, поиск данных, сценарии согласований и передача результата в Ops.

Тендерные подборки, проверка требований, документы, дедлайны и агентные отчеты по процедурам.

Цифровые модели объектов, версии, проектный контекст, инженерные данные и связанные рабочие процессы.

Просмотр BIM, STEP, STL, 3DGS, облаков точек и инженерных материалов внутри единого контура.

Обработка технических форматов, связка моделей с задачами, версиями, отчетами и согласованиями.

Контекстный шлюз для агентов: проектные данные, инструменты, кодовая база и внешние сервисы.

Контракты API, схемы данных, webhooks, события, интеграции и контроль совместимости между модулями.

Оркестрация сервисов, изоляция окружений, scaling policies, probes, secrets и управляемый rollout.

CDN, WAF, R2-хранилище, edge routing, cache policies и защита публичного периметра.

Доступ по принципу least privilege: SSO, MFA, device posture, audit trail и сегментация контуров.

Ролевая матрица, группы, политики доступа, ограничения функций и контроль административных действий.

Права на приложения, рабочие области, действия агентов, документы, отчеты и инженерные данные.

Журнал действий пользователей, агентов и сервисов: изменения, статусы, запросы, публикации и доступы.

Хранение токенов, ключей API, webhook-секретов и конфигураций интеграций в защищенном контуре.

Основная транзакционная база для проектов, ролей, задач, статусов, событий и конфигураций платформы.

Очереди фоновых задач, статусы выполнения, debounce событий, кэширование и быстрые агентные операции.

Индексация проектных материалов, документации, отчетов и контекста для ассистента и поиска.

Контур локальных моделей для приватных сценариев, инженерных данных и корпоративных ограничений.

Маршрутизация задач между облачными и локальными моделями по типу запроса, правам и стоимости.

Запуск ассистентов, выполнение действий, контроль инструментов, журналирование и передача результата в Ops.

Метрики, логи, трассировка, health checks, алерты и диагностика сервисов платформы.

Резервные копии данных, конфигураций, файлов, моделей, журналов и сценариев восстановления.

Сборка, проверки, preview-окружения, controlled rollout, rollback и публикация клиентских модулей.

Описание инфраструктуры кодом: окружения, сети, хранилища, политики, сервисы и переменные.

Хранилище файлов, изображений, моделей, отчетов, txt-материалов и артефактов рабочих процессов.

Загрузка BIM-моделей, версии, разметка, связи с задачами и публикация в рабочие пространства.

Импорт STEP-моделей, технические материалы, карточки проверки и привязка к инженерным задачам.

Проверка STL-геометрии, заметки, версии, визуальный контроль и подготовка производственных материалов.

Gaussian Splatting сцены, визуальные реконструкции объектов и связь с проектным контекстом.

Облака точек, съемка, координатные данные, версии и инженерная привязка к задачам.

Событийные сценарии: входящие запросы, уведомления, автоматические действия и передача статусов.

Документация, регламенты, инструкции, технические заметки и материалы для команд внедрения.

Карта платформенного стека: Hub, Engine, Ops, агенты, данные, интеграции, безопасность и инфраструктура.




































