04Сохранение и встраивание
Сохранение страницы
- Откройте новость в Chrome или Firefox. Закройте cookie-баннер, не принимая рекламные cookies.
- Сохраните страницу одним HTML-файлом через расширение SingleFile. Если вёрстка ломается, используйте «Сохранить как → Веб-страница полностью». Для статичных страниц подойдёт wget:
wget -E -H -k -K -p -e robots=off <url>
- Положите результат в
pages/<region>/index.html, где region — us, cis, in, cn или eu.
- Удалите рекламные, аналитические и трекинговые скрипты (GTM, рекламные SDK, пиксели), чтобы стенд не слал события на реальные сайты. Вёрстку и стили оставьте. Список удалённого запишите в
pages/<region>/NOTES.md.
- Добавьте в
<head> строку <meta name="robots" content="noindex">.
- Сделайте скриншот исходной страницы:
pages/<region>/before.png.
Только для внутреннего демо. Права на контент страниц принадлежат изданиям. Локальные копии не публикуйте и не кладите в открытый репозиторий.
Встраивание
Сразу после последнего абзаца статьи, до комментариев и рекомендаций, вставьте только этот фрагмент:
<div class="news-game"
data-placement="article-end"
data-article-id="us-elias-2-24b"
data-lang="en"></div>
<script async src="http://localhost:8081/widget/v1.js" data-site="demo-us"></script>
| Регион | data-article-id | data-lang | data-site |
| us | us-elias-2-24b | en | demo-us |
| cis | cis-gref-ai-race | ru | demo-cis |
| in | in-ind-wi-odi1 | en | demo-in |
| cn | cn-science-month | zh-CN | demo-cn |
| eu | eu-eucys-2026 | en | demo-eu |
Других правок в HTML страницы для работы виджета быть не должно: так мы проверяем тезис «одна вставка, без изменений CMS».
05Технические требования
Структура репозитория
pages/<region>/index.html копии страниц (origin A: localhost:8080)
widget/v1.js loader (origin B: localhost:8081)
games/<article-id>/ игры (origin B: localhost:8081)
index.html
game.json контент и факты с источниками
assets/
catalog.json article-id → игра, язык, срок актуальности, enabled
Страницы и игры отдаются с разных origin, чтобы изоляция iframe проверялась по-настоящему. Оба сервера поднимаются одной командой (npm run dev или аналог).
Loader — widget/v1.js
- Vanilla JS без зависимостей, не больше 30 KB gzip (цель — меньше 10 KB). Подключается с
async и не блокирует рендер.
- Находит все
.news-game, читает data-атрибуты и запрашивает catalog.json. Если игры нет, она просрочена или выключена, контейнер остаётся скрытым без сдвига вёрстки.
- Показывает компактный тизер «Сыграть по теме» на языке
data-lang, когда блок подходит к области просмотра (IntersectionObserver). Iframe создаётся только по клику.
- Iframe:
sandbox="allow-scripts" без allow-same-origin, allow-top-navigation и allow-popups; loading="lazy", referrerpolicy="no-referrer", title. Каждое дополнительное разрешение обосновать в README.
- Высота iframe меняется по сообщению
resize, максимум 90vh; ширина — 100 % контейнера.
- Стили изолированы через Shadow DOM или префикс. Loader не трогает глобальные стили,
window, историю и URL, не перехватывает скролл.
- При ошибке сети, таймауте 5 с или сообщении
error блок сворачивается, в консоль пишется одно предупреждение, других эффектов нет.
- Kill switch:
enabled: false у игры или сайта в catalog.json скрывает блок.
Протокол postMessage v1
{ ns: "newsgame", v: 1,
type: "ready" | "resize" | "start" | "complete" | "error" | "exit",
gameId: "us-elias-2-24b",
sessionId: "<случайный uuid на запуск>",
payload: {} }
- Loader принимает сообщения только от origin игр и только от своего
iframe.contentWindow; неизвестные ns, v и type игнорирует.
- Игра шлёт сообщения только в
parent с явным targetOrigin, который получает параметром URL и сверяет с allowlist. От страницы принимает только pause и resume.
- События (запрос конфигурации, видимость, запуск, завершение, результат, ошибка, выход) loader выводит в
console.table и отправляет на POST localhost:8081/events (можно писать в JSON-файл). Ответы пользователя и персональные данные не собираются. Флаг preview=1 помечает события как тестовые.
Игры
Браузеры
Последние стабильные Chrome, Safari (iOS и macOS), Firefox, Edge, Chrome на Android. Для Китая дополнительно WeChat in-app browser или эмуляция мобильного Chrome с заблокированными Google-доменами.