Своя HTML-оболочка Web-сборки
Токены экспорта, проверенный пример запуска, canvas и диагностика ожидания.
Своя HTML-оболочка Web-сборки
Custom shell управляет страницей, canvas и UI запуска вокруг совместимого Web export. Она не добавляет Web support установленному C# exporter 1.0.0. Сначала подтвердите рабочий нативный Web template и подходящий проект; статья не заявляет экспортированную C#-игру браузера.
Используйте токены экспорта
В Web export preset задайте html/custom_html_shell путём своего HTML. Exporter заменяет токены; открытие неэкспортированного шаблона напрямую не проверяет запуск.
| Токен | Значение |
|---|---|
| $RECKFELL_URL | Имя сгенерированного loader .js; загрузите до использования Engine. |
| $RECKFELL_CONFIG | Сгенерированный JS config object; вставляйте выражением, не строкой в кавычках. |
| $RECKFELL_THREADS_ENABLED | true/false для feature detection именно этого варианта экспорта. |
| $RECKFELL_HEAD_INCLUDE | Head metadata экспортера плюс html/head_include; сохраните при использовании этих функций. |
| $RECKFELL_PROJECT_NAME | Имя проекта, не универсальный заранее экранированный HTML fragment. |
| $RECKFELL_SPLASH / $RECKFELL_SPLASH_COLOR / $RECKFELL_SPLASH_CLASSES | Сгенерированные путь splash, цвет и styling classes. |
В примере фиксированный title и явный canvas. Его точный inline script проверен с подстановкой config/threads и mock DOM/Engine результатами:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reckfell project</title>
$RECKFELL_HEAD_INCLUDE
</head>
<body>
<p id="status" role="status" aria-live="polite">Loading…</p>
<canvas id="game" tabindex="0" aria-label="Game"></canvas>
<script src="$RECKFELL_URL"></script>
<script>
const status = document.getElementById('status');
const missing = Engine.getMissingFeatures({ threads: $RECKFELL_THREADS_ENABLED });
if (missing.length) {
status.textContent = missing.join('\n');
} else {
const config = $RECKFELL_CONFIG;
const engine = new Engine({ ...config, canvas: document.getElementById('game') });
const timer = setTimeout(() => {
status.textContent = 'Startup is still pending. Check network and console; reload before retrying.';
}, 30000);
engine.startGame().then(() => {
status.textContent = 'Runtime started. Game readiness is reported separately.';
}).catch(error => {
console.error(error);
status.textContent = 'Startup failed. Check network and console; reload before retrying.';
}).finally(() => clearTimeout(timer));
}
</script>
</body>
</html>Таймер 30 секунд только сообщает о продолжающемся ожидании. Он не отменяет сеть, не останавливает WASM и не доказывает отказ. Поздний успешный старт может заменить сообщение. Успех означает вызов main загрузчиком, а не готовность первой игровой сцены или кадра. Если странице нужно это различие, добавьте явный game-to-page readiness message через JavaScriptBridge.
Пути запуска
Для обычного проекта создайте один Engine с exported config и вызовите startGame один раз. Он загружает executable + .wasm, предзагружает mainPack либо executable + .pck, добавляет --main-pack и вызывает start. Не добавляйте .wasm к executable/basePath: init('game') загружает game.wasm, init('game.wasm') запрашивает game.wasm.wasm.
При собственном preloading init использует base path движка без расширения; preloadFile загружает pack и другие файлы; start работает с подготовленной виртуальной FS и явными args. start не предзагружает main pack сам. До старта дождитесь всех обязательных preload. Для buffer вместо URL явно задайте виртуальный destination path.
Не вызывайте startGame повторно ради retry: он снова добавляет --main-pack, а текущий loader разделяет closure-level load/init promises. Одновременные экземпляры могут разделить инициализацию без получения модуля обоими; это воспроизведено с mock modules. Один instance/startup owner на страницу. После неудачной или брошенной попытки изучите диагностику и перезагрузите страницу до retry; тайм-аут не отменяет запуск.
Hosting и отображение
Размещайте exported HTML, loader, WASM, pack и companion files по ожидаемым URL. Нужны HTTP(S), корректная обработка WASM response и headers многопоточного варианта. Feature detection проверяет предпосылки, не скачивание WASM/pack или рендер игры. Проверяйте реальный deployed origin; file:// не является средой приёмки.
Явно выберите canvasResizePolicy: 0 оставляет resize странице, 1 использует project-driven sizing, 2 адаптирует canvas к окну браузера. Для встроенного layout при 0 обычно нужен свой обработчик размеров. Не делайте двух независимых владельцев resize. locale выбирает локализацию игры, а не перевод произвольных DOM labels. experimentalVK означает virtual keyboard, не Vulkan.
onProgress(current,total) сообщает download bytes; total может быть нулём. Тогда показывайте неопределённое ожидание вместо деления на ноль. onPrint/onPrintError получают вывод runtime; для видимых сообщений используйте textContent. Сеть, native errors, game readiness, save durability и service-worker registration — разные состояния.
Текущий init не передаёт все вложенные promise rejections во внешний promise и игнорирует resolved error value инициализации FS. Один catch handler не подтверждает завершённую ошибку или persistence. Проверяйте network/console и хранилище/копии. startGame также не ждёт регистрации service worker.
Границы проверки
20 проверок выполнили реальный Engine/config JavaScript с mock preloader, module, Response и canvas, а также точный shell script с подставленными токенами и mock startup outcomes. Проверены пути, pack, отсутствие canvas, shared init state, ожидание UI и отображение настроек. Реальные template export, WASM, headers/server, browser rendering, accessibility interaction, завершение storage/PWA и C# Web execution не приняты как проверенные. Source, Runtime и SDK не менялись.