- Purpose: Procedural generation, editing, and visualization of fantasy maps for writers, game masters, and cartographers.
- Main Technologies: Vanilla JS/TS, SVG for rendering, Vite for bundling, Biome for linting/formatting.
- Architecture: Moving toward FMG 2.0. The system is divided into four major layers:
- State: The world data (
gridandpackobjects). - Generators: Procedural simulation logic (Model).
- Editors: User-driven map mutations (Controllers).
- Renderers: Visualization into DOM/SVG (View).
- State: The world data (
src/generators/: Generators containing simulation logic (e.g.,heightmap-generator.ts,cultures-generator.ts).src/controllers/: The UI layer — editors and tools that mutate state, plus read-only overviews/dialogs that present it.src/renderers/: Code responsible for transforming world data into SVG overlays.src/io/: Serialization and persistence — save, load, export (legacypublic/modules/io/).src/services/: App-shell & platform lifecycle, unrelated to map state (e.g., PWA installation, auto-update).src/data/: Static content / reference data (e.g., supporters list, heightmap templates).src/types/: Shared TypeScript interfaces and domain models.src/utils/: Generic helper functions.public/: Static assets and NON-MIGRATED JS Code inpublic/modules.public/libs/holds vendored third-party scripts for legacy code only — newsrc/code imports deps from npm (nosrc/libs/).electron/: Main process, preload script and self-update of the desktop app; the renderer is the samesrc/build, served from theapp://scheme.docs/: Domain, architectural documentation and user-facing wiki.src/index.html: CAUTION: Currently a 9K-line monolith containing the entire UI structure, SVG<defs>, and CSS filters.tests/e2e/: Playwright end-to-end tests. Never automatically run Playwright tests when developing.
- Layering Constraint: Generators MUST NOT directly manipulate SVG or DOM elements.
- Data Flow: Generators and Editors mutate the World Data (State). The Renderer reacts to State updates.
- Idempotency: Renderers SHOULD be stateless and idempotent.
- Separation of Concerns: UI logic and simulation logic MUST remain separate.
- Serialization: The entire world state must remain serializable into a single JSON object for
.mapsaving and loading.
- Language: TypeScript is mandatory for all new files.
- Linting and formatting: Enforced via Biome (
biome.json). - Style: Double quotes, no trailing commas, 120 line width, semicolons required.
- Typing: Use explicit TypeScript interfaces for all shared domain objects.
anyshould be avoided. - Imports:
@/*aliasessrc/*(set invite.config.ts+tsconfig.json). Prefer it over deep../../relative paths; keep sibling imports relative.
- Run Locally:
npm run dev - Build:
npm run build - Lint:
npm run lint - Unit Tests:
npm run test(Vitest) - E2E Tests:
npm run test:e2e(Playwright) - Desktop App:
npm run electron(run in Electron with hot reload),npm run electron dist(installers intorelease/) - CI/CD: GitHub Actions enforce linting, building, and playwright tests on PRs.
- Entry Points: Start by inspecting
docs/architecture.mdanddocs/glossary.mdto align with the domain model. - Refactoring Constraints: The project is in a gradual JS -> TS migration. Focus on incremental type safety and extracting logic.
- File Limits:
src/index.htmlis excessively large. DO NOT try to perform large structural changes to it in a single pass. - Dependencies: DO NOT introduce new production dependencies without explicit permission. Keep the bundle lightweight.
- Grid: The underlying Voronoi structure.
- Pack: The aggregate world state (contains
burgs,states,cultures, etc.). - Cell: The smallest indivisible unit of the map.
- Burg: A settlement. Grouped into
States. - Label: Text attached to a State, Burg, or user-defined path. Labels select typography from a shared Label Group.
- Treasury & Taxes: States hold
state.treasuryaccumulated byStates.collectTaxes()from per-dealdeal.tax(sales tax) plusstate.pollTax × (rural + urban). Rates are seeded fromstate.formand jittered per state. Neutrals collect nothing. Details indocs/domain/taxes.md. - Invariants: Saving a
.mapfile MUST preserve the exact world state so it can be reloaded identically.
- Legacy Globals: The codebase heavily relies on implicit global state (
packandgridon thewindow). Be extremely cautious when refactoring these to explicit parameters. index.html: A massive monolith serving as the primary UI template. It can easily break if structural tags are accidentally nested incorrectly.
docs/glossary.md: Domain vocabulary definitions.docs/architecture.md: The guiding blueprint for FMG 2.0.
- Use concise and descriptive variable names, don't use unusual abbreviations.
- Prefer laconic but clear code.
- Save space, I like my code to be compact.
- Avoid over-engineering, keep it simple and vertically readable.