Fantasy-Map-Generator/docs/architecture-globals.md

3.8 KiB

Fantasy Map Generator — Global Variable Architecture

Critical: main.js is NOT an ES Module

public/main.js (and all other public/modules/**/*.js files) are loaded as plain <script defer> tags — not ES modules. Every var, let, const, and function declaration at the top level of these files is automatically a property of window (the global object).

Key globals exposed by main.js

Variable Type Description
scale number Current D3 zoom scale factor (initially 1)
viewX number Current D3 zoom translate X (initially 0)
viewY number Current D3 zoom translate Y (initially 0)
graphWidth number Map canvas width in SVG user units
graphHeight number Map canvas height in SVG user units
svgWidth number SVG element rendered width (px)
svgHeight number SVG element rendered height (px)
pack object Packed voronoi graph + all generated data
grid object Initial grid graph
viewbox D3 selection D3 selection of #viewbox <g>
svg D3 selection D3 selection of #map <svg>
zoom D3 zoom behaviour The active d3-zoom instance
seed string Current map seed
options object Global render/UI options

Rule for TypeScript/ES-module code in src/

All main.js globals are declared as ambient globals in src/types/global.ts. Just use them directly — no window. prefix, no (window as any), no globalThis. TypeScript already knows their types.

// ✅ CORRECT — declared in src/types/global.ts, use as bare globals
buildCameraBounds(viewX, viewY, scale, graphWidth, graphHeight);
viewbox.on("zoom.webgl", handler);

// ❌ WRONG — unnecessary indirection
(window as any).scale(globalThis as any).viewX;

The only exception is a Node/test-env guard where the global may genuinely not exist:

if (typeof viewbox === "undefined") return; // guard for Node test env
viewbox.on("zoom.webgl", handler); // then use directly

In webgl-layer-framework.ts the syncTransform() method correctly reads:

buildCameraBounds(viewX, viewY, scale, graphWidth, graphHeight);

Why this matters for new WebGL/canvas overlays

Any canvas or WebGL overlay that must stay pixel-aligned with the SVG viewbox must read scale, viewX, viewY at render time — these are live globals updated on every D3 zoom event. Do not cache them at module load time.

Other public/modules globals of note

toggleRelief, drawRelief, undrawRelief, rerenderReliefIcons, layerIsOn, turnButtonOn, turnButtonOff, byId, tip, rn, P, gauss — all utility functions defined in public JS files and available globally.

Module loading order

  1. public/libs/*.js — third-party (d3, jQuery, etc.)
  2. src/utils/index.ts, src/modules/index.ts, src/renderers/index.ts — ES modules (bundled by Vite); these run before the deferred legacy scripts
  3. public/main.js and public/modules/**/*.js — deferred plain scripts

Implication: ES modules in src/ that call WebGL2LayerFramework.register() at module load time are safe because the framework class is instantiated at the bottom of webgl-layer-framework.ts (an ES module), which runs before the deferred main.js. main.js then calls WebGL2LayerFramework.init() inside generateMapOnLoad().