This directory contains the browser DCML compatibility layer. Keep changes small and place new compatibility code at the boundary that owns it.
index.html loads the browser shell first, then the mod layer:
BrowserShell/browser_api.jscreates the browserwindow.apishim.Modloader/mod_compat.jscreateswindow.ModCompatfor DCML hooks.Modloader/mod_loader.jsparses ASAR files, indexes overrides, installs resource interceptors, and exposeswindow.ModLoader.Modloader/Sortable.min.jsandModloader/markdown_viewer.jsprovide local UI helpers for mod ordering and README rendering.Modloader/manager.jsrenders the selection/config UI and callsModLoader.init(selectedIds).- The Tyrano engine scripts and
BrowserShell/electron_latest.jsare loaded after the user starts the game.
mod_loader.js
- Owns ASAR parsing, file indexing, path normalization, resource interception,
hook execution, and the public
window.ModLoaderAPI. - Does not render UI, persist mod selection, or implement generic Electron APIs.
mod_compat.js
- Owns the minimal Electron preload / Node compatibility surface used by
hook.js:electronAPI,require('fs'),require('path'),Buffer, andprocess. - Maps DCML config paths such as
plugins/config/<id>.jsontolocalStorage.mod_config_<id>. - Is not a general filesystem implementation; add only APIs that real mods need.
manager.js
- Owns the browser UI for selecting, importing, ordering, configuring, and importing/exporting mod-related data, plus the pre-start save archive UI.
- Honors
defaultEnabled: falseon built-in manifest entries; entries without that field keep the historical default-enabled behavior. - Does not parse ASAR internals except through
ModLoaderhelper APIs. - Local imported ASAR files are intentionally session-only.
markdown_viewer.js
- Owns the manager About page's local README Markdown rendering helper.
- Escapes raw HTML from Markdown input and supports only the project README's basic Markdown patterns.
- Does not fetch remote Markdown or participate in game startup.
BrowserShell/browser_api.js
- Owns the browser replacement for the original Electron preload
window.api. - Storage, dialogs, fullscreen, and browser file download/upload helpers belong here.
BrowserShell/electron_latest.js
- Owns Tyrano runtime patches that are needed after the engine is loaded.
- Engine behavior overrides belong here, not in
BrowserShell/browser_api.js.
ModLoader.init(selectedIds)is all-or-nothing for a non-empty selection. Missing manifest entries and ASAR fetch, read, or parse failures must reject with the affected mod id;initializedis set only after every selected mod has been indexed. Failed batches clear their partial index and remain retryable in the same page session.- Invalid local ASAR files must be rejected before the manager adds them to the selectable mod list.
- Save archive actions must wait for
window.api.storage.ready. Imports must validate every recognized entry with the browser shell's side-effect-free decoder and reject duplicate save keys before writing; a failed flush must attempt to restore the pre-import values. - Resource interceptors must be installed once. Repeated
init()calls should not wrap browser APIs again. - ASAR header and file entries must be validated before indexing:
finite non-negative integer
offset/size, andoffset + sizeinside the data section. - Resource lookup uses normalized same-origin paths. Query strings and hashes are stripped before ASAR matching.
- Local imported mods with the same id intentionally override built-in mods for the current session.
- Cross-origin,
blob:,data:, andjavascript:URLs should not be claimed by ASAR path matching. - Public APIs that report per-mod metadata must inspect that mod's own ASAR or
local buffer. Do not infer per-mod flags from the merged
fileIndex. - Resource interceptors replace only the resolved URL. They must preserve the
rest of each browser API call, such as XHR
async/ credentials arguments andfetch()init/Requestoptions, CSSsetPropertypriority, callback timing, and wrapper prototype behavior.
Runtime debug entrypoints are documented in ../tool/README.md. Keep the full
helper list there so DevTools usage notes have one owner.
For loader changes, at minimum run:
npm run checkFor a tighter edit loop while working only on the loader, npm run check:modloader
runs the focused ModLoader VM harness.
Then manually test:
- Start with no mods selected.
- Start with built-in mods selected.
- Confirm a missing or damaged selected ASAR stops startup, names the failed mod, and succeeds after the resource is restored and startup is retried.
- Import a local ASAR, reorder it, and start.
- Confirm resource overrides work for same-origin absolute URLs and query/hash cache-busted URLs.
- Open a DCML hook mod that reads
window.electronAPI.