Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"Bash(npm start)",
"Bash(rm:*)",
"Bash(npm run dev:*)",
"Bash(npm run test:*)",
"Bash(npx tsc:*)",
"Bash(find:*)",
"Bash(cp:*)",
"Bash(ls:*)",
"Bash(mkdir:*)",
"Bash(dir:*)",
"Bash(npm run:*)",
"Bash(timeout 10 npm run dev)",
"Bash(timeout 15 npm run dev)"
],
"deny": []
}
}
8 changes: 8 additions & 0 deletions .gemini/knowledge/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
This knowledge base contains information on procedural generation techniques relevant to the TypeScript/React medieval town generator in the `web` directory. The goal is to provide a reference for extending and improving the generator.

The following documents are available:

* `voronoi_diagrams.md`: Using Voronoi diagrams for district and road generation.
* `wave_function_collapse.md`: Explanation and use cases for WFC in city building.
* `l-systems.md`: How to use L-Systems for generating organic road networks.
* `generation_pipeline.md`: A document outlining a complete, step-by-step pipeline for generating a city, from terrain to detailing.
61 changes: 61 additions & 0 deletions .gemini/knowledge/generation_pipeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Town Generation Pipeline

This document outlines a step-by-step pipeline for generating a medieval town using the techniques described in the other knowledge base documents.

## 1. Terrain Generation

First, we need to generate the terrain for the town. We can use a noise function like Perlin noise to create a heightmap.

* **Input:** Map dimensions.
* **Output:** A 2D array representing the heightmap.

## 2. District Generation

Next, we use a Voronoi diagram to divide the map into districts.

* **Input:** A set of seed points.
* **Output:** A set of polygons representing the districts.
* **Relevant Files:** `web/src/services/voronoi.ts`, `web/src/services/wards/*`

## 3. Road Network Generation

We can use the edges of the Voronoi diagram or an L-System to generate the road network.

* **Input:** The Voronoi diagram or an L-System grammar.
* **Output:** A set of road segments.
* **Relevant Files:** `web/src/services/voronoi.ts`

## 4. Building Generation

For each district, we can use Wave Function Collapse to generate the buildings.

* **Input:** A tileset and rules for each district.
* **Output:** A set of building models.
* **Relevant Files:** `web/src/building/*`, `web/src/types/simple-wfc.ts`

## 5. Detail Placement

Finally, we can add details like props, vegetation, and other features to the town.

* **Input:** The generated town map.
* **Output:** A complete town map with details.

## Example Pipeline

```typescript
// Example of a high-level generation pipeline
import { generateTerrain } from './terrain';
import { generateDistricts } from './districts';
import { generateRoads } from './roads';
import { generateBuildings } from './buildings';
import { placeDetails } from './details';

function generateTown(width: number, height: number) {
const terrain = generateTerrain(width, height);
const districts = generateDistricts(terrain);
const roads = generateRoads(districts);
const buildings = generateBuildings(districts);
const town = placeDetails(terrain, districts, roads, buildings);
return town;
}
```
51 changes: 51 additions & 0 deletions .gemini/knowledge/l-systems.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Using L-Systems for Road Generation

L-Systems (Lindenmayer Systems) are a type of formal grammar that can be used to generate complex, branching structures. We can use L-Systems to create organic-looking road networks in our town.

## 1. Defining the Grammar

An L-System consists of an alphabet, an axiom (the starting string), and a set of production rules.

* **Alphabet:** The set of symbols that can be used in the system. For example, `F` could mean "draw forward", `+` could mean "turn right", and `-` could mean "turn left".
* **Axiom:** The initial string that the system starts with.
* **Rules:** A set of rules that define how each symbol in the alphabet is replaced in each iteration.

## 2. Implementing the L-System

We can create a simple L-System interpreter that takes a grammar and generates a sequence of drawing commands.

### Implementation

1. **Define the Grammar:** Create a grammar object with an alphabet, axiom, and rules.
2. **Iterate:** Repeatedly apply the rules to the axiom to generate a long string of commands.
3. **Interpret:** Parse the string of commands and generate the road network.

```typescript
// Example L-System implementation
interface LSystemGrammar {
axiom: string;
rules: { [key: string]: string };
}

function generateLSystem(grammar: LSystemGrammar, iterations: number): string {
let result = grammar.axiom;
for (let i = 0; i < iterations; i++) {
result = result.split('').map(char => grammar.rules[char] || char).join('');
}
return result;
}

// Example usage
const roadGrammar: LSystemGrammar = {
axiom: 'F',
rules: { 'F': 'F+F-F-F+F' },
};

const roadCommands = generateLSystem(roadGrammar, 3);

// Interpret the commands to draw the road network
```

## Existing Code

There is no existing L-System implementation in the codebase. This would be a new addition to the project.
51 changes: 51 additions & 0 deletions .gemini/knowledge/voronoi_diagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Using Voronoi Diagrams for Town Generation

Voronoi diagrams are a powerful tool for dividing a space into regions. In the context of our town generator, they can be used to create organic-looking districts and road networks.

## 1. Generating Districts

We can use Voronoi diagrams to partition the map into different wards or districts. The `web/src/services/wards` directory already contains different ward types. We can use Voronoi cells to define the boundaries of these wards.

### Implementation

1. **Generate Seed Points:** Create a set of random points within the map boundaries. The number of points will correspond to the number of districts.
2. **Create Voronoi Diagram:** Use a library like `d3-voronoi` to generate the Voronoi diagram from the seed points.
3. **Assign Wards:** Assign a ward type from the `web/src/services/wards` directory to each Voronoi cell.

```typescript
// Example using a hypothetical Voronoi library
import { Voronoi } from 'some-voronoi-library';
import { CommonWard } from './services/wards/CommonWard';

const points = [/* array of seed points */];
const voronoi = new Voronoi(points, {width: 1000, height: 1000});
const diagram = voronoi.diagram();

const wards = diagram.cells.map(cell => {
// Assign a ward type to each cell
return new CommonWard(cell.polygon);
});
```

## 2. Generating Road Networks

The edges of the Voronoi cells can be used to generate a basic road network. The Delaunay triangulation of the seed points can also be used to create a more connected network.

### Implementation

1. **Extract Edges:** Get the edges from the Voronoi diagram.
2. **Filter Edges:** Remove short or unnecessary edges.
3. **Create Roads:** Create road segments from the filtered edges.

```typescript
// Example using a hypothetical Voronoi library
const edges = diagram.edges;
const roads = edges.map(edge => {
// Create a road segment from the edge
return new Road(edge.start, edge.end);
});
```

## Existing Code

The file `web/src/services/voronoi.ts` already exists. This file can be extended to include the logic for generating districts and road networks.
39 changes: 39 additions & 0 deletions .gemini/knowledge/wave_function_collapse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Using Wave Function Collapse for Building Generation

Wave Function Collapse (WFC) is an algorithm for procedural generation that can create complex and detailed structures from a small set of rules. We can use WFC to generate buildings within our town.

## 1. Defining Tiles

First, we need to define a set of tiles that will be used to construct the buildings. These tiles can represent different parts of a building, such as walls, roofs, doors, and windows.

The `web/src/building` directory contains classes like `Model`, `Patch`, and `CurtainWall` that can be used to define the geometry of our tiles.

## 2. Defining Rules

Next, we need to define the rules that govern how the tiles can be placed next to each other. For example, a window tile can only be placed next to a wall tile.

These rules can be defined in a JSON file or directly in the code.

## 3. Implementing WFC

There are several WFC libraries available for TypeScript. We can use one of these libraries to implement the WFC algorithm.

The `web/src/types/simple-wfc.d.ts` and `web/src/types/simple-wfc.ts` files suggest that a WFC library may already be in use. We should investigate this further.

### Implementation

1. **Create a Tileset:** Define the tiles and their rules.
2. **Initialize WFC:** Create a WFC model with the tileset.
3. **Run WFC:** Run the WFC algorithm to generate a building.

```typescript
// Example using a hypothetical WFC library
import { WFC } from 'some-wfc-library';

const tileset = { /* tiles and rules */ };
const wfc = new WFC(tileset);
const building = wfc.generate();

// Convert the generated building into a Model
const model = new Model(building.patches);
```
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.iml
/Export
/.idea
/Assets
Loading