From 538cc3423a878466e27cc820246fc4d680e993d1 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 29 Aug 2025 14:36:34 +0200 Subject: [PATCH 1/5] fix: 1227 --- index.html | 2 +- modules/ui/units-editor.js | 11 ++++++++--- versioning.js | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 3c0ba0f3..0c8a1e58 100644 --- a/index.html +++ b/index.html @@ -8141,7 +8141,7 @@ - + diff --git a/modules/ui/units-editor.js b/modules/ui/units-editor.js index a30e9a7d..aa63e64a 100644 --- a/modules/ui/units-editor.js +++ b/modules/ui/units-editor.js @@ -121,11 +121,16 @@ function editUnits() { function addRuler() { if (!layerIsOn("toggleRulers")) toggleRulers(); + + const width = Math.min(graphWidth, svgWidth); + const height = Math.min(graphHeight, svgHeight); const pt = byId("map").createSVGPoint(); - (pt.x = graphWidth / 2), (pt.y = graphHeight / 4); + pt.x = width / 2; + pt.y = height / 4; const p = pt.matrixTransform(viewbox.node().getScreenCTM().inverse()); - const dx = graphWidth / 4 / scale; - const dy = (rulers.data.length * 40) % (graphHeight / 2); + + const dx = width / 4 / scale; + const dy = (rulers.data.length * 40) % (height / 2); const from = [(p.x - dx) | 0, (p.y + dy) | 0]; const to = [(p.x + dx) | 0, (p.y + dy) | 0]; rulers.create(Ruler, [from, to]).draw(); diff --git a/versioning.js b/versioning.js index a785e90e..1094599c 100644 --- a/versioning.js +++ b/versioning.js @@ -13,7 +13,7 @@ * Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2 */ -const VERSION = "1.108.11"; +const VERSION = "1.108.12"; if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function"); { From f73a8906cebe1d8206a88c2be2018483c5b34ac9 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:20:03 +0200 Subject: [PATCH 2/5] Add comprehensive GitHub Copilot instructions for Fantasy Map Generator (#1233) * Initial plan * Add comprehensive GitHub Copilot instructions for Fantasy Map Generator Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com> * chore: copilot instructions --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Azgaar <26469650+Azgaar@users.noreply.github.com> Co-authored-by: Azgaar --- .github/copilot-instructions.md | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..698d23ae --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,89 @@ +# Fantasy Map Generator + +Azgaar's Fantasy Map Generator is a client-side JavaScript web application for creating fantasy maps. It generates detailed fantasy worlds with countries, cities, rivers, biomes, and cultural elements. + +Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here. + +## Working Effectively + +- **CRITICAL**: This is a static web application - NO build process needed. No npm install, no compilation, no bundling. +- Run the application using HTTP server (required - cannot run with file:// protocol): + - `python3 -m http.server 8000` - takes 2-3 seconds to start +- Access at: `http://localhost:8000` + +## Validation + +- Always manually validate any changes by: + 1. Starting the HTTP server (NEVER CANCEL - wait for full startup) + 2. Navigate to the application in browser + 3. Click the "►" button to open the menu and generate a new map + 4. **CRITICAL VALIDATION**: Verify the map generates with countries, cities, roads, and geographic features + 5. Test UI interaction: click "Layers" button, verify layer controls work + 6. Test regeneration: click "New Map!" button, verify new map generates correctly +- **Known Issues**: Google Analytics and font loading errors are normal (blocked external resources) + +## Repository Structure + +### Core Files + +- `index.html` - Main application entry point +- `main.js` - Core application logic +- `versioning.js` - Version management and update handling + +### Key Directories + +- `modules/` - core functionality modules: + - `modules/ui/` - UI components (editors, tools, style management) + - `modules/dynamic/` - runtime modules (export, installation) + - `modules/renderers/` - drawing and rendering logic +- `utils/` - utility libraries (math, arrays, strings, etc.) +- `styles/` - visual style presets (JSON files) +- `libs/` - Third-party libraries (D3.js, TinyMCE, etc.) +- `images/` - backgrounds, UI elements +- `charges/` - heraldic symbols and coat of arms elements +- `config/` - Heightmap templates and configurations +- `heightmaps/` - Terrain generation data + +## Common Tasks + +### Making Code Changes + +1. Edit JavaScript files directly (no compilation needed) +2. Refresh browser to see changes immediately +3. **ALWAYS test map generation** after making changes +4. Update version in `versioning.js` for all changes +5. Update file hashes in `index.html` for changed files (format: `file.js?v=1.108.1`) + +### Debugging Map Generation + +- Open browser developer tools console +- Look for timing logs, e.g. "TOTAL: ~0.76s" +- Map generation logs show each step (heightmap, rivers, states, etc.) +- Error messages will indicate specific generation failures + +### Testing Different Map Types + +- Use "New Map!" button for quick regeneration +- Access "Layers" menu to change map visualization +- Available presets: Political, Cultural, Religions, Biomes, Heightmap, Physical, Military + +## Troubleshooting + +### Application Won't Load + +- Ensure using HTTP server (not file://) +- Check console for JavaScript errors +- Verify all files are present in repository + +### Map Generation Fails + +- Check browser console for error messages +- Look for specific module failures in generation logs +- Try refreshing page and generating new map + +### Performance Issues + +- Map generation should complete in ~1 second for standard configurations +- If slower, check browser console for errors + +Remember: This is a sophisticated client-side application that generates complete fantasy worlds with political systems, geography, cultures, and detailed cartographic elements. Always validate that your changes preserve the core map generation functionality. From 6afa016920cb46397ee5f53d3730794505a452b1 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 02:21:52 +0000 Subject: [PATCH 3/5] docs: add comprehensive CLAUDE.md for AI assistants Add detailed documentation to help AI assistants understand and work with the Fantasy Map Generator codebase, including: - Project architecture and technology stack - Directory structure and file organization - Data model and core concepts (pack object, Voronoi mesh) - Code conventions and module patterns - Development workflow and versioning process - Common development tasks and patterns - Performance considerations and best practices - Troubleshooting guide and quick reference This guide provides AI assistants with essential context about the codebase's unique characteristics (no build system, global object pattern, typed arrays, D3.js rendering) to enable more effective contributions. --- CLAUDE.md | 832 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 832 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..a2438d37 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,832 @@ +# CLAUDE.md - AI Assistant Guide for Fantasy Map Generator + +## Project Overview + +**Fantasy Map Generator** (FMG) is a free web-based application for creating and editing fantasy maps. It's a massive client-side JavaScript application designed for fantasy writers, game masters, and cartographers. + +- **Repository**: https://github.com/Azgaar/Fantasy-Map-Generator +- **Live App**: https://azgaar.github.io/Fantasy-Map-Generator +- **Language**: Pure JavaScript (ES6+) +- **License**: MIT +- **Primary Author**: Azgaar (azgaar.fmg@yandex.com) + +## Architecture & Technology Stack + +### Core Technologies + +- **Pure JavaScript (ES6+)**: NO build system, transpilation, or bundling +- **D3.js v7**: SVG manipulation, data visualization, zoom/pan interactions +- **jQuery 3.1.1 + jQuery UI**: DOM manipulation, dialogs, UI components +- **Progressive Web App (PWA)**: Service worker caching, offline support, IndexedDB storage + +### Key Libraries (`/libs/`) + +``` +d3.min.js # Main visualization library +delaunator.min.js # Delaunay triangulation for Voronoi mesh +alea.min.js # Seedable random number generator +three.min.js # 3D rendering support +jszip.min.js # ZIP file creation for exports +polylabel.min.js # Label placement optimization +tinymce/ # Rich text editor for notes +``` + +### Architecture Pattern + +**Global Object Pattern**: No module bundler, everything attached to `window` object: + +```javascript +// Global data structures (from main.js:151-158) +let grid = {}; // Initial Voronoi graph +let pack = {}; // Main packed data structure +let seed; // Map generation seed +let mapId; // Unique map identifier +let mapHistory = []; // Undo/redo history +let modules = {}; // Module initialization flags +let notes = []; // User notes +``` + +## Directory Structure + +``` +Fantasy-Map-Generator/ +├── index.html # 8,184-line monolithic HTML (entire UI) +├── main.js # 1,288 lines - initialization, globals, SVG setup +├── versioning.js # Version management (currently v1.108.11) +├── sw.js # Service worker for PWA caching +│ +├── modules/ # Core application logic (232 JS files) +│ ├── dynamic/ # Dynamically imported modules +│ │ ├── editors/ # Advanced editors (states, religions, cultures) +│ │ ├── overview/ # Data visualization tools +│ │ └── *.js # Auto-update, installation, hierarchy-tree +│ ├── io/ # Input/Output operations +│ │ ├── cloud.js # Cloud storage (Dropbox) +│ │ ├── export.js # Map export functionality +│ │ ├── load.js # Map loading +│ │ └── save.js # Map saving +│ ├── renderers/ # SVG rendering (12 files) +│ │ ├── draw-borders.js +│ │ ├── draw-heightmap.js +│ │ ├── draw-markers.js +│ │ └── ... +│ └── ui/ # UI editors and tools (~35 files) +│ ├── editors.js # Common editor functions +│ ├── options.js # Map configuration +│ └── ... +│ +├── utils/ # Utility functions (15 files) +│ ├── arrayUtils.js +│ ├── colorUtils.js +│ ├── commonUtils.js # debounce, throttle +│ ├── graphUtils.js # Graph algorithms (297 lines) +│ ├── pathUtils.js # SVG path operations (222 lines) +│ └── ... +│ +├── charges/ # 400+ SVG heraldic symbols +├── components/ # Reusable UI components +├── config/ # Heightmap template configurations +├── heightmaps/ # Precreated heightmap resources +├── images/ # Application images/icons +├── styles/ # 12 JSON theme presets (default, night, etc.) +│ +└── .github/ + ├── pull_request_template.md + └── ISSUE_TEMPLATE/ +``` + +## Key Files + +### Entry Points + +- **index.html** (line 1-8184): Entire UI structure, loads all scripts +- **main.js** (line 1-1288): Initializes globals, SVG layers, data structures +- **versioning.js**: Current version: `1.108.11` (semantic versioning) + +### Core Generators + +```javascript +modules/burgs-and-states.js # City/state generation (1,018 lines) +modules/cultures-generator.js # Culture system (1,039 lines) +modules/names-generator.js # Name generation (3,371 lines) +modules/heightmap-generator.js # Terrain generation (445 lines) +modules/river-generator.js # River systems (507 lines) +modules/routes-generator.js # Road/trail generation (537 lines) +modules/religions-generator.js # Religion system (757 lines) +modules/military-generator.js # Military units (405 lines) +modules/markers-generator.js # Map markers (1,163 lines) +modules/coa-generator.js # Coat of arms logic (1,015 lines) +modules/coa-renderer.js # COA SVG rendering (2,527 lines) +modules/provinces-generator.js # Province subdivision (302 lines) +modules/zones-generator.js # Zone assignment (430 lines) +``` + +## Data Model + +### Primary Data Structure: `pack` Object + +The `pack` object is the heart of FMG's data model. It contains the entire map state using **typed arrays** for performance: + +```javascript +pack = { + cells: { + i: Uint32Array, // Cell indices + v: Array, // Adjacent vertices + c: Array, // Adjacent cells + b: Uint8Array, // Border flags + h: Uint8Array, // Height (0-100) + temp: Int8Array, // Temperature + prec: Uint8Array, // Precipitation + f: Uint16Array, // Feature (biome) ID + t: Int8Array, // Terrain type + haven: Uint16Array, // Harbor ID + harbor: Uint8Array, // Harbor presence + fl: Uint16Array, // Flux (river flow) + r: Uint16Array, // River ID + conf: Uint8Array, // River confluence + pop: Float32Array, // Population density + culture: Uint16Array, // Culture ID + burg: Uint16Array, // Settlement ID + road: Uint16Array, // Road ID + route: Uint16Array, // Route ID + crossroad: Uint16Array, + province: Uint16Array, + state: Uint16Array, // State ownership + religion: Uint16Array + }, + vertices: { + p: Array, // Point coordinates [x, y] + v: Array, // Adjacent vertices + c: Array // Adjacent cells + }, + features: Array, // Biome/terrain features + cultures: Array, // Culture definitions + states: Array, // Political states + burgs: Array, // Cities/towns/settlements + religions: Array, // Religion definitions + provinces: Array, // Province data + rivers: Array, // River definitions + markers: Array, // Map markers + notes: Array // User notes +} +``` + +### Typed Array Constants + +```javascript +// From main.js:16-20 +const INT8_MAX = 127; +const UINT8_MAX = 255; +const UINT16_MAX = 65535; +const UINT32_MAX = 4294967295; +``` + +### Map Generation Pipeline + +``` +Heightmap Generation + ↓ +Voronoi/Delaunay Mesh + ↓ +Biomes & Climate + ↓ +Rivers & Water Features + ↓ +Cultures Assignment + ↓ +States & Capitals + ↓ +Burgs (Cities/Towns) + ↓ +Provinces Subdivision + ↓ +Routes (Roads/Trails) + ↓ +Religions Distribution + ↓ +Military Units + ↓ +Final Rendering +``` + +## SVG Layer Organization + +FMG uses 70+ predefined SVG layer groups in specific render order (from main.js:40-94): + +```javascript +// Background to foreground rendering order +ocean → oceanLayers → oceanPattern → lakes → landmass → +texture → terrs → biomes → cells → rivers → terrain → +regions → borders → routes → temperature → coastline → +ice → population → emblems → labels → icons → armies → +markers → fogging → ruler → debug +``` + +**Important**: When modifying rendering, respect this layer order to avoid z-index issues. + +## Code Conventions & Style + +### General Style + +1. **Strict Mode**: Every file starts with `"use strict";` +2. **No Semicolons**: Generally omitted (but inconsistent) +3. **Naming Conventions**: + - `camelCase` for variables and functions + - `PascalCase` for classes + - `SCREAMING_SNAKE_CASE` for constants +4. **Comments**: Minimal; code is mostly self-documenting +5. **String Quotes**: Mixed single and double quotes (no standard) + +### Module Patterns + +**IIFE (Immediately Invoked Function Expression)**: + +```javascript +// From burgs-and-states.js:3 +window.BurgsAndStates = (() => { + const generate = () => { + // Implementation + }; + + return { generate }; +})(); + +// Usage elsewhere: +BurgsAndStates.generate(); +``` + +**Global Function Pattern**: + +```javascript +// From draw-borders.js:3 +function drawBorders() { + // Direct global function +} +``` + +**Utility Module Pattern**: + +```javascript +// From utils/commonUtils.js +function debounce(func, ms) { /* ... */ } +function throttle(func, ms) { /* ... */ } +// Directly callable globally +``` + +### Loading Strategy + +**index.html** loads scripts in three phases: + +1. **Libraries** (D3, jQuery, etc.) +2. **Core Modules** (synchronous, no `defer`) +3. **UI Modules** (with `defer` attribute) +4. **Dynamic Imports** (ES6 `import()` for lazy loading) + +Example from index.html: +```html + + + + + + + + + + +``` + +### Debug Flags + +```javascript +// From main.js:5-11 +const PRODUCTION = location.hostname && + location.hostname !== "localhost" && + location.hostname !== "127.0.0.1"; +const DEBUG = JSON.safeParse(localStorage.getItem("debug")) || {}; +const INFO = true; +const TIME = true; // Performance timing +const WARN = true; +const ERROR = true; + +// Usage: +TIME && console.time("placeCapitals"); +// ... expensive operation ... +TIME && console.timeEnd("placeCapitals"); +``` + +## Development Workflow + +### No Build System + +- **Zero build configuration**: No webpack, rollup, or bundlers +- **No package.json**: No npm dependencies +- **No transpilation**: No Babel or TypeScript +- **Direct file editing**: Edit JS → Refresh browser → See changes + +### Local Development + +```bash +# Python simple server +python -m http.server 8080 + +# PHP built-in server +php -S localhost:8080 + +# Then visit: http://localhost:8080 +``` + +### Versioning Process + +**Manual 3-step versioning** (from pull_request_template.md): + +1. **Update VERSION** in `versioning.js`: + ```javascript + const VERSION = "1.108.12"; // Increment using semver + ``` + +2. **Update file hashes** in `index.html` for all changed files: + ```html + + ``` + +3. **Update changelog** in `showUpdateWindow()` function (versioning.js) if user-facing + +### Git Workflow + +**Commit Message Format** (inferred from git log): + +``` +(): + +Examples: +fix(v1.108.11): add external icons to export in base64 format +feat(ai-generator): update supported AI models list +refactor: drawReliefIcons, v1.108.4 +perf: set text-rendering to optimizeSpeed, v1.108.1 +chore: update version to 1.108.8 +``` + +**Types**: +- `feat`: New feature +- `fix`: Bug fix +- `refactor`: Code restructuring +- `perf`: Performance improvement +- `chore`: Maintenance tasks +- `docs`: Documentation changes + +**Scopes**: Optional, often includes version number or component name + +### Pull Request Requirements + +From `.github/pull_request_template.md`: + +**Required**: +- [ ] Description of change and motivation +- [ ] Type of change (bug fix, feature, refactor, docs, other) +- [ ] Version updated in `versioning.js` +- [ ] Changed files hash updated in `index.html` + +**Before submitting**: +1. Test locally (no automated tests) +2. Check console for errors +3. Verify map generation still works +4. Update version following semver + +## Common Development Tasks + +### Adding a New Feature + +1. **Identify the module type**: + - Generator? → `modules/` + - UI Editor? → `modules/ui/` + - Renderer? → `modules/renderers/` + - Utility? → `utils/` + +2. **Create the module file**: + ```javascript + "use strict"; + + window.MyNewFeature = (() => { + const generate = () => { + TIME && console.time("myNewFeature"); + // Implementation + TIME && console.timeEnd("myNewFeature"); + }; + + return { generate }; + })(); + ``` + +3. **Add script tag to index.html**: + ```html + + ``` + +4. **Update versioning**: + - Increment VERSION in `versioning.js` + - Update hash in `index.html` + - Add changelog entry if user-facing + +### Modifying the Data Model + +1. **Update pack structure** in relevant generator +2. **Update save/load** in `modules/io/save.js` and `modules/io/load.js` +3. **Test with existing .map files** to ensure backward compatibility +4. **Update any renderers** that use the new data + +### Adding a New Renderer + +1. **Create renderer file** in `modules/renderers/`: + ```javascript + "use strict"; + + function drawMyFeature() { + const { cells, myFeatures } = pack; + const container = svg.select("#myFeatureLayer"); + + // D3 rendering logic + container.selectAll("path") + .data(myFeatures) + .join("path") + .attr("d", d => d.path) + .attr("fill", d => d.color); + } + ``` + +2. **Create SVG layer** in main.js: + ```javascript + let myFeatureLayer = viewbox.append("g") + .attr("id", "myFeatureLayer"); + ``` + +3. **Add to render pipeline** in appropriate location + +### Debugging Tips + +1. **Use DEBUG flags**: + ```javascript + DEBUG && console.log("Debug info:", data); + TIME && console.time("expensiveOperation"); + ``` + +2. **Check the debug SVG layer**: + ```javascript + debug.append("circle") + .attr("cx", x) + .attr("cy", y) + .attr("r", 5) + .attr("fill", "red"); + ``` + +3. **Use browser DevTools**: + - Network tab: Check script loading + - Console: Look for TIME logs + - Sources: Set breakpoints + +4. **Test map generation**: + - Generate → Verify no console errors + - Save → Load → Verify data integrity + - Export → Check output quality + +## Testing Approach + +**No formal testing framework**: +- No Jest, Mocha, or automated tests +- Manual testing only +- User reports via GitHub issues + +**Manual testing checklist**: +1. Generate new map with default settings +2. Generate with various custom settings +3. Load existing .map files +4. Test all editors (heightmap, states, cultures, etc.) +5. Export in all formats (SVG, PNG, JSON) +6. Check console for errors/warnings +7. Test on multiple browsers (Chrome, Firefox, Safari) + +## Performance Considerations + +### Optimization Strategies + +1. **Typed Arrays**: Use for large datasets + ```javascript + cells.h = new Uint8Array(n); // Heights 0-255 + cells.pop = new Float32Array(n); // Population + ``` + +2. **D3 Data Binding**: Efficient DOM updates + ```javascript + container.selectAll("path") + .data(features, d => d.id) // Key function + .join("path") // Efficient enter/update/exit + ``` + +3. **Debouncing/Throttling**: For frequent events + ```javascript + const onMouseMove = debounce(handleMouseMove, 100); + ``` + +4. **Quadtree for Spatial Queries**: + ```javascript + let burgsTree = d3.quadtree(); + burgsTree.add([x, y]); + const nearest = burgsTree.find(x, y, radius); + ``` + +5. **IndexedDB**: For large map storage + ```javascript + // See libs/indexedDB.js + ``` + +## Important Patterns & Anti-Patterns + +### DO: + +✅ Use typed arrays for cell data +✅ Respect SVG layer rendering order +✅ Use TIME flags for performance monitoring +✅ Follow IIFE pattern for new modules +✅ Update version numbers consistently +✅ Test backward compatibility with old .map files +✅ Use D3 data binding for DOM updates +✅ Check for null/undefined before accessing pack data + +### DON'T: + +❌ Add npm dependencies (no build system) +❌ Use ES6 modules (not supported in current architecture) +❌ Modify global data structures directly without updating renderers +❌ Add large libraries (keep bundle size manageable) +❌ Break backward compatibility without migration logic +❌ Add features without updating save/load functionality +❌ Forget to update version hash in index.html +❌ Mix rendering layers (respect z-order) + +## Common Patterns in Codebase + +### Random Number Generation + +```javascript +// Use seeded random for reproducibility +const rand = aleaPRNG(seed); +const value = rand(); // 0-1 + +// Gaussian distribution +const value = gauss(mean, deviation, min, max, rounds); +``` + +### Cell Iteration + +```javascript +const { cells } = pack; +const n = cells.i.length; + +for (let i = 0; i < n; i++) { + if (cells.h[i] < 20) continue; // Skip water + // Process land cells +} +``` + +### D3 SVG Path Creation + +```javascript +const path = d3.line() + .x(d => d[0]) + .y(d => d[1]) + .curve(d3.curveBasis); + +const pathString = path(points); +``` + +### Graph Traversal + +```javascript +// BFS example from graphUtils.js +const queue = [startCell]; +const visited = new Uint8Array(cells.i.length); + +while (queue.length) { + const cell = queue.shift(); + if (visited[cell]) continue; + visited[cell] = 1; + + cells.c[cell].forEach(neighbor => { + if (!visited[neighbor]) queue.push(neighbor); + }); +} +``` + +## Key Concepts + +### Voronoi/Delaunay Mesh + +FMG uses a Voronoi diagram as the base map structure: + +- **Cells**: Voronoi regions representing map areas +- **Vertices**: Points where 3+ cells meet +- **Edges**: Borders between cells +- **Delaunay Triangulation**: Dual graph for efficient pathfinding + +**Implementation**: Custom `Voronoi` class in `modules/voronoi.js` using Delaunator library + +### Heightmap System + +Heights stored as `Uint8Array` (0-255): +- **0-19**: Ocean depths +- **20**: Sea level +- **21-99**: Land elevations +- **100+**: Mountains/peaks (clamped to 255) + +### Culture & State System + +**Cultures**: Linguistic/ethnic groups with naming patterns +**States**: Political entities with territories, capitals, military + +Both use expansion algorithms based on cell scoring and distance from capitals. + +### Name Generation + +Sophisticated system in `modules/names-generator.js` (3,371 lines): +- Cultural naming patterns +- Procedural phoneme generation +- Linguistic rules for realistic names +- Separate generators for burgs, states, cultures, features + +## File Modification Guidelines + +### When Editing index.html + +- **Line count**: 8,184 lines - VERY large file +- **Structure**: UI components inline (not templated) +- **Script tags**: Update version hash when modifying JS files +- **Dialogs**: jQuery UI dialogs defined inline +- **Be careful**: Easy to break HTML structure + +### When Editing main.js + +- **Global scope**: Everything here is globally accessible +- **SVG layers**: Order matters (lines 40-94) +- **Constants**: Typed array max values defined here +- **Initialization**: Core setup happens here + +### When Editing Generators + +- **Self-contained**: Each generator should be independent +- **Timing**: Wrap in TIME && console.time/timeEnd +- **Error handling**: Use WARN && console.warn for issues +- **Data mutations**: Update pack object directly + +### When Editing Renderers + +- **Layer awareness**: Know which SVG layer you're drawing to +- **Clear old content**: Remove previous render before redrawing +- **D3 data binding**: Use .join() for efficient updates +- **Performance**: Large renders should be optimized + +## Resources + +### Documentation + +- **Project Wiki**: https://github.com/Azgaar/Fantasy-Map-Generator/wiki +- **Data Model**: https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Data-model +- **Trello Board**: https://trello.com/b/7x832DG4/fantasy-map-generator +- **Blog**: https://azgaar.wordpress.com + +### Community + +- **Discord**: https://discordapp.com/invite/X7E84HU +- **Reddit**: https://www.reddit.com/r/FantasyMapGenerator +- **GitHub Issues**: https://github.com/Azgaar/Fantasy-Map-Generator/issues + +### Support + +- **Patreon**: https://www.patreon.com/azgaar +- **Email**: azgaar.fmg@yandex.com + +## Troubleshooting Common Issues + +### Map Won't Generate + +1. Check console for errors +2. Verify all scripts loaded (Network tab) +3. Check localStorage isn't corrupted +4. Try clearing browser cache + +### Save/Load Failures + +1. Check IndexedDB quota +2. Verify .map file format (should be valid JSON) +3. Check version compatibility +4. Look for migration errors in console + +### Performance Issues + +1. Reduce number of cells (Options → Map Size) +2. Disable unused layers +3. Use simpler rendering styles +4. Check for memory leaks in console + +### Rendering Glitches + +1. Verify SVG layer order +2. Check for NaN values in coordinates +3. Ensure paths are valid SVG syntax +4. Test in different browsers + +## Best Practices for AI Assistants + +### When Analyzing Code + +1. **Start with the data model**: Understand `pack` structure +2. **Check dependencies**: See what functions/modules are used +3. **Look for patterns**: IIFE modules, global functions, D3 usage +4. **Trace data flow**: How data moves through generation pipeline + +### When Making Changes + +1. **Test locally first**: No CI/CD, manual testing required +2. **Update version properly**: Follow 3-step process +3. **Maintain backward compatibility**: Old .map files should still load +4. **Document complex logic**: Code is under-commented +5. **Check performance**: Use TIME flags to measure + +### When Refactoring + +1. **Small incremental changes**: Large refactors are risky +2. **Keep the same API**: Don't break existing integrations +3. **Test all features**: Generator, editors, save/load, export +4. **Consider deprecation**: Don't remove features abruptly + +### When Adding Features + +1. **Check existing code**: Similar features might exist +2. **Follow existing patterns**: IIFE for modules, global for utils +3. **Update save/load**: Persist new data properly +4. **Add UI if needed**: Users should access the feature +5. **Update documentation**: At least in comments/changelog + +## Quick Reference + +### File to Edit By Task + +| Task | Files to Edit | +|------|--------------| +| Add new generator | `modules/my-generator.js`, `index.html` (script tag) | +| Modify UI editor | `modules/ui/my-editor.js` | +| Change rendering | `modules/renderers/draw-my-feature.js` | +| Add utility function | `utils/myUtils.js` | +| Update save format | `modules/io/save.js`, `modules/io/load.js` | +| Change map options | `modules/ui/options.js`, `index.html` (UI) | +| Add SVG layer | `main.js` (lines 40-94), renderer file | +| Update version | `versioning.js`, `index.html` (all script tags) | + +### Common Functions + +| Function | Location | Purpose | +|----------|----------|---------| +| `rn(value, decimals)` | `utils/numberUtils.js` | Round number | +| `rand(min, max)` | Random utilities | Random in range | +| `gauss(mean, dev, ...)` | `utils/probabilityUtils.js` | Gaussian distribution | +| `debounce(fn, ms)` | `utils/commonUtils.js` | Debounce function | +| `P(probability)` | Probability utils | Random boolean | +| `ra(array)` | Array utils | Random array element | + +### Common D3 Patterns + +```javascript +// Select SVG layer +const layer = svg.select("#myLayer"); + +// Data binding +layer.selectAll("path") + .data(features, d => d.id) + .join("path") + .attr("d", d => d.path); + +// Zoom/pan +const zoom = d3.zoom() + .scaleExtent([1, 20]) + .on("zoom", zoomed); + +svg.call(zoom); +``` + +--- + +## Summary + +Fantasy Map Generator is a **unique codebase** that prioritizes: + +1. **Accessibility**: Runs anywhere without build tools +2. **Simplicity**: Direct file editing, no complex tooling +3. **Performance**: Typed arrays, efficient algorithms +4. **User experience**: Rich UI with extensive customization + +When working on FMG, embrace its philosophy: **pragmatic simplicity over modern complexity**. The lack of build tools is intentional, making it easy for contributors to jump in without setup overhead. + +--- + +*Last Updated: 2025-11-14* +*Current Version: 1.108.11* +*This guide is for AI assistants working on Fantasy Map Generator codebase.* From acc2d112f3b2fcd966d74cca3daa6f6ab3f1b224 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 02:33:16 +0000 Subject: [PATCH 4/5] feat: add default map setting feature Add ability to set a specific map as the default that opens on load: - Add 'Open default map' option to onload behavior dropdown - Implement saveAsDefaultMap() to store map as default in IndexedDB - Implement clearDefaultMap() to remove default map setting - Modify checkLoadParameters() to load default map when configured - Add UI buttons in Save dialog for setting/clearing default map - Update version to 1.108.12 and hash in index.html Users can now: 1. Open any map they want as default 2. Go to Options > Onload behavior > Select "Open default map" 3. Save > Click "Set as default" button 4. The map will now open automatically every time This sets the foundation for the planned time-based worldbuilding and lore database features by ensuring users always start with their primary world map. --- index.html | 14 ++++++++++++-- main.js | 16 ++++++++++++++++ modules/io/save.js | 26 ++++++++++++++++++++++++++ versioning.js | 2 +- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 3c0ba0f3..9175879e 100644 --- a/index.html +++ b/index.html @@ -1830,6 +1830,7 @@ @@ -6087,6 +6088,15 @@ browser +
+ Default map + + +

Maps are saved in .map format, that can be loaded back via the Load in menu. There is no way to restore the progress if file is lost. Please keep old save files on your machine or cloud storage as backups. @@ -8118,7 +8128,7 @@ - + @@ -8163,7 +8173,7 @@ - + diff --git a/main.js b/main.js index 848ff3c5..4f4bdb63 100644 --- a/main.js +++ b/main.js @@ -291,6 +291,22 @@ async function checkLoadParameters() { return; } + // check if there is a default map saved to indexedDB + if (byId("onloadBehavior").value === "default") { + try { + const blob = await ldb.get("defaultMap"); + if (blob) { + WARN && console.warn("Loading default map"); + uploadMap(blob); + return; + } else { + WARN && console.warn("No default map set, generating random map"); + } + } catch (error) { + ERROR && console.error(error); + } + } + // check if there is a map saved to indexedDB if (byId("onloadBehavior").value === "lastSaved") { try { diff --git a/modules/io/save.js b/modules/io/save.js index 304fef59..7a9236c7 100644 --- a/modules/io/save.js +++ b/modules/io/save.js @@ -167,6 +167,32 @@ async function saveToStorage(mapData, showTip = false) { showTip && tip("Map is saved to the browser storage", false, "success"); } +// save current map as the default map +async function saveAsDefaultMap() { + if (customization) return tip("Map cannot be saved in EDIT mode, please complete the edit and retry", false, "error"); + + try { + const mapData = prepareMapData(); + const blob = new Blob([mapData], {type: "text/plain"}); + await ldb.set("defaultMap", blob); + tip("Map is set as default and will open on load", true, "success", 5000); + } catch (error) { + ERROR && console.error(error); + tip("Failed to set default map", true, "error", 3000); + } +} + +// clear the default map setting +async function clearDefaultMap() { + try { + await ldb.set("defaultMap", null); + tip("Default map cleared", false, "success", 2000); + } catch (error) { + ERROR && console.error(error); + tip("Failed to clear default map", false, "error", 2000); + } +} + // download map file function saveToMachine(mapData, filename) { const blob = new Blob([mapData], {type: "text/plain"}); diff --git a/versioning.js b/versioning.js index a785e90e..1094599c 100644 --- a/versioning.js +++ b/versioning.js @@ -13,7 +13,7 @@ * Example: 1.102.2 -> Major version 1, Minor version 102, Patch version 2 */ -const VERSION = "1.108.11"; +const VERSION = "1.108.12"; if (parseMapVersion(VERSION) !== VERSION) alert("versioning.js: Invalid format or parsing function"); { From 769d3a31bbececdb5d54cf103410942852629e08 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 02:57:07 +0000 Subject: [PATCH 5/5] feat: add Obsidian vault integration for modern Markdown notes Add comprehensive Obsidian integration as intermediate step toward PostgreSQL migration, enabling modern Markdown-based note editing: **Features:** - Obsidian Local REST API integration for vault access - Coordinate-based note matching (searches vault YAML frontmatter) - Shows top 5-8 closest matches when clicking burgs/markers - Modern Markdown editor with live preview - [[Wikilink]] support for connecting notes - "Open in Obsidian" button to jump to native app - Configuration UI for API setup and testing **Technical Implementation:** - modules/io/obsidian-bridge.js - Core API integration layer - modules/ui/obsidian-notes-editor.js - Markdown editor UI - modules/ui/obsidian-config.js - Configuration panel - OBSIDIAN_INTEGRATION.md - Complete setup/usage guide **Coordinate Matching:** - Parses YAML frontmatter for x/y coordinates - Calculates distance to clicked element - Supports nested (coordinates.x) and flat (x:) formats - Handles missing FMG IDs (common with PostgreSQL imports) **User Workflow:** 1. Configure Obsidian REST API connection 2. Click burg/marker in FMG 3. System finds matching notes by coordinates 4. Select note or create new one 5. Edit in modern Markdown editor 6. Save syncs to Obsidian vault instantly This replaces the "Win95-style TinyMCE" editor with a clean, modern Markdown experience while maintaining compatibility with the eventual PostgreSQL backend migration. Users can edit notes in either FMG or Obsidian - both stay in sync via file system. Version: 1.108.13 --- OBSIDIAN_INTEGRATION.md | 270 ++++++++++++++++++ index.html | 109 +++++++- modules/io/obsidian-bridge.js | 416 ++++++++++++++++++++++++++++ modules/ui/obsidian-config.js | 73 +++++ modules/ui/obsidian-notes-editor.js | 358 ++++++++++++++++++++++++ versioning.js | 2 +- 6 files changed, 1226 insertions(+), 2 deletions(-) create mode 100644 OBSIDIAN_INTEGRATION.md create mode 100644 modules/io/obsidian-bridge.js create mode 100644 modules/ui/obsidian-config.js create mode 100644 modules/ui/obsidian-notes-editor.js diff --git a/OBSIDIAN_INTEGRATION.md b/OBSIDIAN_INTEGRATION.md new file mode 100644 index 00000000..5389cd03 --- /dev/null +++ b/OBSIDIAN_INTEGRATION.md @@ -0,0 +1,270 @@ +# Obsidian Vault Integration for Fantasy Map Generator + +## Overview + +Fantasy Map Generator now supports deep integration with your Obsidian vault for managing map lore and notes! This allows you to: + +- Store all your world lore in Markdown format +- Edit notes in a modern Markdown editor (no more Win95-style TinyMCE!) +- Automatically link map elements to Obsidian notes by coordinates +- Keep your notes in sync between FMG and Obsidian +- Use [[wikilinks]] to connect related notes +- Edit in either FMG or Obsidian - changes sync both ways + +## Setup + +### 1. Install Obsidian Local REST API Plugin + +1. Open Obsidian +2. Go to **Settings** → **Community Plugins** +3. Click **Browse** and search for "Local REST API" +4. Install and **Enable** the plugin +5. Go to **Settings** → **Local REST API** +6. Copy your **API Key** (you'll need this!) +7. Note the **Server Port** (default: 27123) + +### 2. Configure in Fantasy Map Generator + +1. Open Fantasy Map Generator +2. Go to **Menu** → **Tools** → **⚙ Obsidian** +3. Enter your settings: + - **API URL**: `http://127.0.0.1:27123` (default) + - **API Key**: Paste from Obsidian plugin settings + - **Vault Name**: Name of your Obsidian vault +4. Click **Test Connection** to verify +5. Click **Save Configuration** + +## Usage + +### Linking Map Elements to Notes + +When you click on a **burg** or **marker** in FMG: + +1. FMG searches your Obsidian vault for notes with matching coordinates in YAML frontmatter +2. Shows you the top 5-8 closest matches +3. You select the note you want, or create a new one + +### Note Format + +Notes in your vault should have YAML frontmatter like this: + +```markdown +--- +fmg-id: burg123 +fmg-type: burg +coordinates: + x: 234.5 + y: 456.7 + lat: 45.23 + lon: -73.45 +tags: + - capital + - settlement + - ancient +aliases: + - Eldoria + - The Ancient City +--- + +# Eldoria + +The ancient capital sits upon the [[River Mystral]], founded in year 1203. + +## History + +The city was established by [[King Aldric the First]]... + +## Notable Locations + +- [[The Grand Library]] +- [[Temple of the Seven Stars]] +- [[Market Square]] +``` + +### Coordinate Matching + +Since your burgs/markers may have been imported from PostgreSQL without FMG IDs, the system matches by **X/Y coordinates**: + +- FMG extracts the coordinates from the clicked element +- Searches all `.md` files in your vault for matching `x:` and `y:` values +- Calculates distance and shows closest matches +- You pick the right one! + +### Supported Coordinate Formats + +The system recognizes these formats in YAML frontmatter: + +```yaml +# Nested object (recommended) +coordinates: + x: 123.4 + y: 567.8 + +# Or flat +x: 123.4 +y: 567.8 + +# Case insensitive +X: 123.4 +Y: 567.8 +``` + +### Creating New Notes + +If no matches are found: + +1. FMG offers to create a new note +2. Enter a name (e.g., "Eldoria") +3. Optionally specify a folder (e.g., "Locations/Cities") +4. FMG generates a template with coordinates +5. Opens in the Markdown editor +6. Saved directly to your Obsidian vault! + +### Editing Notes + +The modern Markdown editor includes: + +- **Live preview**: Toggle between edit/preview modes +- **[[Wikilinks]]**: Link to other notes in your vault +- **Syntax highlighting**: Clean monospace font +- **Open in Obsidian**: Button to jump to the note in Obsidian app +- **Save to Vault**: Changes sync immediately + +### Using Wikilinks + +Create connections between notes: + +```markdown +The [[King Aldric the First]] ruled from [[Eldoria]]. +The city controls access to [[River Mystral]]. +``` + +When you save in FMG, these links work in Obsidian! + +## Migration from PostgreSQL + +If you have existing lore in PostgreSQL with coordinates: + +1. Export your data to Markdown files with YAML frontmatter +2. Include `x`, `y`, `lat`, `lon` in the frontmatter +3. Place files in your Obsidian vault +4. FMG will auto-match by coordinates! + +Example export script template: + +```python +for location in locations: + frontmatter = f"""--- +fmg-type: {location.type} +coordinates: + x: {location.x} + y: {location.y} + lat: {location.lat} + lon: {location.lon} +tags: {location.tags} +--- + +# {location.name} + +{location.description} +""" + with open(f"vault/{location.name}.md", "w") as f: + f.write(frontmatter) +``` + +## Tips & Tricks + +### Organize Your Vault + +Create folders for different types: + +``` +My Vault/ +├── Locations/ +│ ├── Cities/ +│ ├── Landmarks/ +│ └── Regions/ +├── Characters/ +├── History/ +└── Lore/ +``` + +### Use Templates + +Create Obsidian templates for different element types: + +- `Templates/City.md` +- `Templates/Landmark.md` +- `Templates/Character.md` + +### Search and Graph + +In Obsidian: + +- Use **Search** (`Ctrl+Shift+F`) to find notes by coordinates +- Use **Graph View** to see connections between locations +- Use **Tags** to organize by type + +### Sync Across Devices + +Use Obsidian Sync or Git to keep your vault synced across computers! + +## Troubleshooting + +### Connection Failed + +- Make sure Obsidian is running +- Verify the Local REST API plugin is enabled +- Check the port number (default 27123) +- Try restarting Obsidian + +### No Matches Found + +- Check that your notes have `x:` and `y:` fields in frontmatter +- Verify coordinates are numbers, not strings +- Try increasing the search radius + +### Changes Not Appearing in Obsidian + +- Obsidian should auto-detect file changes +- If not, try switching to another note and back +- Or close/reopen the note + +## Advanced + +### Custom Coordinate Systems + +If you use a different coordinate system: + +1. Map your coordinates to FMG's system +2. Store both in frontmatter: +```yaml +coordinates: + x: 234.5 # FMG coordinates + y: 456.7 + custom_x: 1000 # Your system + custom_y: 2000 +``` + +### Database Bridge + +For the future PostgreSQL migration: + +1. Keep coordinates in both Obsidian and database +2. Use coordinates as the join key +3. Sync changes via API +4. Eventually replace file storage with DB + +## Future Features + +Planned enhancements: + +- [ ] Time slider - view notes across historical periods +- [ ] Automatic tagging by region/culture +- [ ] Bulk import from database +- [ ] Real-time collaboration +- [ ] Custom Markdown extensions + +--- + +**Enjoy your modern, Markdown-powered world-building! 🗺️✨** diff --git a/index.html b/index.html index 9175879e..b644322f 100644 --- a/index.html +++ b/index.html @@ -2062,6 +2062,9 @@ Namesbase + @@ -4963,6 +4966,107 @@ + +

+ + + +