mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-04-03 22:17:24 +02:00
bmad-init
This commit is contained in:
parent
b6484a783f
commit
3047aefd40
294 changed files with 38091 additions and 55 deletions
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
stepsCompleted: [1]
|
||||
inputDocuments: []
|
||||
session_topic: "WebGL + SVG Layered Rendering Architecture for Relief Icons"
|
||||
session_goals: "Explore all viable approaches for achieving correct layer ordering when mixing WebGL (Three.js) and SVG rendering for the relief icons layer; specifically evaluate and expand on the multi-SVG/multi-DOM-element architecture; surface edge cases, risks, and non-obvious possibilities"
|
||||
selected_approach: "AI-Recommended"
|
||||
techniques_used: []
|
||||
ideas_generated: []
|
||||
context_file: ""
|
||||
---
|
||||
|
||||
# Brainstorming Session — WebGL Relief Icons Rendering Architecture
|
||||
|
||||
**User:** Azgaar
|
||||
**Date:** 2026-03-12
|
||||
**Project:** Fantasy-Map-Generator
|
||||
|
||||
---
|
||||
|
||||
## Session Overview
|
||||
|
||||
**Topic:** WebGL + SVG Layered Rendering Architecture — Relief Icons
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Explore all viable approaches for mixing WebGL (Three.js) and SVG while preserving correct layer ordering
|
||||
- Thoroughly evaluate the "split into multiple DOM elements, one per layer" proposal
|
||||
- Surface edge cases, risks, performance characteristics, and non-obvious alternatives
|
||||
- Push the idea space far past the obvious before organizing
|
||||
|
||||
### Core Problem Statement
|
||||
|
||||
The relief icons layer is currently SVG. The proposed change renders it via Three.js WebGL for performance. Three approaches have been considered:
|
||||
|
||||
1. **Canvas beside the SVG** — loses all layer interleaving (layers can't be placed between each other)
|
||||
2. **WebGL inside `<foreignObject>`** — correct layering, but catastrophically slow (FBO composite on every frame)
|
||||
3. **Split SVG into multiple DOM elements (1 per layer)** — some layers canvas/WebGL, some SVG, each independently moveable in the DOM to reconstruct layer order
|
||||
|
||||
The user needs to explore Option 3 deeply and discover any other viable approaches.
|
||||
|
||||
---
|
||||
214
_bmad-output/project-context.md
Normal file
214
_bmad-output/project-context.md
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
---
|
||||
project_name: "Fantasy-Map-Generator"
|
||||
user_name: "Azgaar"
|
||||
date: "2026-03-12"
|
||||
sections_completed:
|
||||
["technology_stack", "architecture", "language_rules", "framework_rules", "testing_rules", "code_quality", "workflow"]
|
||||
---
|
||||
|
||||
# Project Context for AI Agents
|
||||
|
||||
_Critical rules and patterns that AI agents must follow when implementing code in this project. Focuses on unobvious details that agents might otherwise miss._
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack & Versions
|
||||
|
||||
| Technology | Version | Role |
|
||||
| ---------- | -------- | ----------------------------------------------- |
|
||||
| TypeScript | ^5.9.3 | Source language for `src/` |
|
||||
| Vite | ^7.3.1 | Build tool & dev server |
|
||||
| Biome | 2.3.13 | Linter & formatter (replaces ESLint + Prettier) |
|
||||
| Vitest | ^4.0.18 | Unit & browser unit tests |
|
||||
| Playwright | ^1.57.0 | E2E tests |
|
||||
| D3 | ^7.9.0 | SVG rendering & data manipulation |
|
||||
| Delaunator | ^5.0.1 | Voronoi/Delaunay triangulation |
|
||||
| Three.js | ^0.183.2 | 3D globe view |
|
||||
| Polylabel | ^2.0.1 | Polygon label placement |
|
||||
| Node.js | >=24.0.0 | Runtime requirement |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
**Hybrid codebase**: New code lives in `src/` (TypeScript, bundled by Vite). Legacy code lives in `public/modules/` (plain JavaScript, loaded as-is). The two halves communicate through `window` globals.
|
||||
|
||||
**Vite config quirk**: `root` is `./src`, `publicDir` is `../public`. All paths in config files must be relative to `src/`.
|
||||
|
||||
---
|
||||
|
||||
## Critical Implementation Rules
|
||||
|
||||
### Global Module Pattern (MOST IMPORTANT)
|
||||
|
||||
Every TypeScript generator module follows this mandatory pattern:
|
||||
|
||||
1. **Define type and declare global** at the top of the file:
|
||||
|
||||
```ts
|
||||
declare global {
|
||||
var ModuleName: ModuleClass;
|
||||
}
|
||||
```
|
||||
|
||||
2. **Implement as a class**:
|
||||
|
||||
```ts
|
||||
class ModuleClass {
|
||||
// methods
|
||||
}
|
||||
```
|
||||
|
||||
3. **Register on `window` at the bottom of the file** (last line):
|
||||
|
||||
```ts
|
||||
window.ModuleName = new ModuleClass();
|
||||
```
|
||||
|
||||
4. **Import the module** in `src/modules/index.ts` (side-effect import):
|
||||
```ts
|
||||
import "./module-name";
|
||||
```
|
||||
|
||||
**Utility functions used by legacy JS** must also be attached to `window` via `src/utils/index.ts`.
|
||||
|
||||
### Global Variables
|
||||
|
||||
Key globals declared in `src/types/global.ts` — always use these directly, never redeclare:
|
||||
|
||||
- `pack` (`PackedGraph`) — main data structure with all cell/feature data
|
||||
- `grid` — raw grid data before packing
|
||||
- `graphWidth`, `graphHeight` — map canvas dimensions
|
||||
- `svgWidth`, `svgHeight` — SVG element dimensions
|
||||
- `TIME` / `WARN` / `ERROR` / `DEBUG` — logging flags
|
||||
- `seed` — current map seed string
|
||||
|
||||
D3 selection globals (for SVG manipulation): `svg`, `viewbox`, `rivers`, `labels`, `burgLabels`, `burgIcons`, `markers`, `defs`, `coastline`, `lakes`, `terrs`, `routes`, etc.
|
||||
|
||||
### Data Structures & Typed Arrays
|
||||
|
||||
The `PackedGraph.cells` object stores most data in **typed arrays** for performance. Always use the utility functions:
|
||||
|
||||
```ts
|
||||
import {createTypedArray, getTypedArray} from "../utils";
|
||||
|
||||
// Create typed array (auto-selects Uint8/Uint16/Uint32 based on maxValue)
|
||||
createTypedArray({maxValue: cells.i.length, length: n});
|
||||
|
||||
// Get constructor only
|
||||
getTypedArray(maxValue);
|
||||
```
|
||||
|
||||
**Never use plain JS arrays for numeric cell data** — always use typed arrays.
|
||||
|
||||
### Land Height Threshold
|
||||
|
||||
Land cells have height `>= 20`. Water/ocean cells have height `< 20`. This threshold is a project-wide constant:
|
||||
|
||||
```ts
|
||||
const isLand = (cellId: number) => cells.h[cellId] >= 20;
|
||||
```
|
||||
|
||||
Use exactly `>= 20` — no magic numbers, no alternative thresholds.
|
||||
|
||||
### Language-Specific Rules
|
||||
|
||||
- **TypeScript strict mode** is on: `strict`, `noUnusedLocals`, `noUnusedParameters`, `noFallthroughCasesInSwitch` all enabled.
|
||||
- **`noEmit: true`** — TypeScript is typechecking only; Vite handles transpilation.
|
||||
- **`isolatedModules: true`** — each file must be independently compilable; avoid type-only exports without `type` keyword.
|
||||
- **Module resolution**: `bundler` mode with `allowImportingTsExtensions` — use `.ts` extensions in imports within `src/`.
|
||||
- **`noExplicitAny`** is disabled — `any` is permitted where needed (legacy interop).
|
||||
- **`noNonNullAssertion`** is disabled — `!` non-null assertions are allowed.
|
||||
- **Always use `Number.isNaN()`** — never `isNaN()` (Biome `noGlobalIsNan` rule is an error).
|
||||
- **Always provide radix to `parseInt()`** — `parseInt(str, 10)` (Biome `useParseIntRadix` rule).
|
||||
- **Use template literals** over string concatenation (Biome `useTemplate` warning).
|
||||
- Import `rn` from `"../utils"` for rounding — `rn(value, decimals)`.
|
||||
|
||||
### Code Organization
|
||||
|
||||
- `src/modules/` — generator classes (one domain per file, kebab-case filename)
|
||||
- `src/renderers/` — SVG draw functions (prefixed `draw-`, registered as `window.drawX`)
|
||||
- `src/utils/` — pure utility functions exported as named exports
|
||||
- `src/types/` — TypeScript type declarations (`PackedGraph.ts`, `global.ts`)
|
||||
- `src/config/` — static configuration data
|
||||
- `public/modules/` — legacy JavaScript (do not add TypeScript here)
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
| Item | Convention | Example |
|
||||
| ----------------- | ---------------------------------- | --------------------------------------- |
|
||||
| Files | kebab-case | `burgs-generator.ts`, `draw-borders.ts` |
|
||||
| Classes | PascalCase + domain suffix | `BurgModule`, `BiomesModule` |
|
||||
| Window globals | PascalCase | `window.Burgs`, `window.Biomes` |
|
||||
| Utility functions | camelCase | `rn`, `minmax`, `createTypedArray` |
|
||||
| Constants | SCREAMING_SNAKE_CASE | `TYPED_ARRAY_MAX_VALUES` |
|
||||
| Unit test files | `*.test.ts` (co-located in `src/`) | `commonUtils.test.ts` |
|
||||
| E2E test files | `*.spec.ts` (in `tests/e2e/`) | `burgs.spec.ts` |
|
||||
|
||||
---
|
||||
|
||||
## Testing Rules
|
||||
|
||||
### Unit Tests (Vitest)
|
||||
|
||||
- Co-locate `*.test.ts` files alongside source files in `src/utils/`
|
||||
- Use `describe` / `it` / `expect` from `"vitest"`
|
||||
- Default `vitest` command runs these (no browser needed)
|
||||
- `vitest --config=vitest.browser.config.ts` for browser-context unit tests
|
||||
|
||||
### E2E Tests (Playwright)
|
||||
|
||||
- Files go in `tests/e2e/` with `.spec.ts` extension
|
||||
- Always clear cookies and storage in `beforeEach`:
|
||||
```ts
|
||||
await context.clearCookies();
|
||||
await page.evaluate(() => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
});
|
||||
```
|
||||
- Use seed parameter for deterministic maps: `page.goto("/?seed=test-NAME&width=1280&height=720")`
|
||||
- **Wait for map generation** before asserting:
|
||||
```ts
|
||||
await page.waitForFunction(() => (window as any).mapId !== undefined, {timeout: 60000});
|
||||
```
|
||||
- Fixed viewport for consistent rendering: 1280×720 (set in `playwright.config.ts`)
|
||||
- Access global state via `page.evaluate(() => (window as any).pack)`
|
||||
- Only Chromium is tested (single browser project in CI)
|
||||
|
||||
---
|
||||
|
||||
## Code Quality & Style (Biome)
|
||||
|
||||
- **Scope**: Biome only lints/formats `src/**/*.ts` — not `public/` legacy JS
|
||||
- **Formatter**: spaces (not tabs), double quotes for JS strings
|
||||
- **Organize imports** is auto-applied on save
|
||||
- Run `npm run lint` to check+fix, `npm run format` to format only
|
||||
- Rules to always follow:
|
||||
- `Number.isNaN()` not `isNaN()`
|
||||
- `parseInt(x, 10)` always with radix
|
||||
- Template literals over concatenation
|
||||
- No unused variables or imports (error level)
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
- **Dev server**: `npm run dev` (Vite, port 5173)
|
||||
- **Build**: `npm run build` (tsc typecheck + Vite bundle → `dist/`)
|
||||
- **E2E in dev**: requires dev server running; CI builds first then previews on port 4173
|
||||
- **Netlify deploy**: `base` URL switches to `/` when `NETLIFY` env var is set
|
||||
- **No vitest config file at root** — default Vitest config is inlined in `package.json` scripts; browser config is in `vitest.browser.config.ts`
|
||||
|
||||
---
|
||||
|
||||
## Common Anti-Patterns to Avoid
|
||||
|
||||
- **Do NOT** use plain `Array` for cell data in `pack.cells` — use typed arrays
|
||||
- **Do NOT** define `var` in modules without `declare global` — all globals must be typed in `src/types/global.ts`
|
||||
- **Do NOT** add new modules to `public/modules/` — new code goes in `src/modules/` as TypeScript
|
||||
- **Do NOT** call `isNaN()` — use `Number.isNaN()`
|
||||
- **Do NOT** call `parseInt()` without a radix
|
||||
- **Do NOT** skip the `window.ModuleName = new ModuleClass()` registration at the bottom of module files
|
||||
- **Do NOT** import modules in `src/modules/index.ts` with anything other than a bare side-effect import (`import "./module-name"`)
|
||||
- **Do NOT** hardcode the land height threshold — use `>= 20` and reference the convention
|
||||
Loading…
Add table
Add a link
Reference in a new issue