4.4 KiB
4.4 KiB
Cursebreaker Interactive Map
An interactive web-based map viewer for "The Black Grimoire: Cursebreaker" game, built with Rust (Axum) and Leaflet.js.
Features
- Optimized Tile Loading: Uses merged tiles to reduce HTTP requests
- Zoom level 0: ~31 tiles (4×4 merged)
- Zoom level 1: ~105 tiles (2×2 merged)
- Zoom level 2: ~345 tiles (original tiles)
- Lossless Compression: All tiles use lossless WebP for optimal quality
- High-Performance Rendering: Serves tiles directly from SQLite database
- Interactive Navigation: Pan and zoom through the game world
- Dark Theme UI: Game-themed dark interface with collapsible sidebar
- Real-time Coordinates: Display tile and pixel coordinates while hovering
Architecture
Backend (Rust + Axum)
- Tile Server: Serves WebP-compressed map tiles from SQLite database
- API Endpoints:
GET /api/tiles/:z/:x/:y- Retrieve tile at coordinates (x, y) and zoom level zGET /api/bounds- Get map bounds (min/max x/y coordinates)GET /- Serve static frontend files
Frontend (Leaflet.js)
- Image Overlay Layer: Each merged tile is rendered as a positioned image overlay
- Merged Tile System: Reduces HTTP requests by merging tiles at lower zoom levels:
- Zoom 0: 4×4 original tiles merged into 512px images (~31 total requests)
- Zoom 1: 2×2 original tiles merged into 512px images (~105 total requests)
- Zoom 2: Original 512px tiles (1×1, ~345 total requests)
- Fixed Coordinate System: Uses Leaflet's CRS.Simple with tiles positioned at their exact pixel coordinates
Prerequisites
- Rust (latest stable)
- SQLite database at
../cursebreaker.dbwithminimap_tilestable populated
Running the Map Viewer
First Time Setup
-
Generate all map tiles (only needed once, or after updating minimap images):
cd cursebreaker-parser cargo run --bin image-parser --releaseThis processes all PNG files and automatically generates all 3 zoom levels (takes ~1.5 minutes)
-
Start the map server:
cd ../cursebreaker-map cargo run --release -
Open in browser: Navigate to
http://127.0.0.1:3000
Subsequent Runs
Just start the server (step 2 above). All tiles are stored in the database.
Database Configuration
By default, the server looks for the database at ../cursebreaker.db. You can override this with the DATABASE_URL environment variable:
DATABASE_URL=/path/to/cursebreaker.db cargo run --release
Future Enhancements
The sidebar includes placeholders for upcoming features:
- Icon Filtering: Toggle visibility of shops, resources, fast travel points, workbenches, etc.
- Map Markers: Display game entities (shops, resources, NPCs) with clickable info popups
- Search: Find locations by name
- Pathfinding: Calculate routes between points
- Layer Control: Toggle different map overlays
Project Structure
cursebreaker-map/
├── Cargo.toml # Rust dependencies
├── src/
│ └── main.rs # Axum web server
├── static/
│ ├── index.html # Main HTML page
│ ├── style.css # Styling (dark theme)
│ └── map.js # Leaflet map initialization
└── README.md
Performance Notes
- Merged Tiles: Reduces HTTP requests by up to 91% at lowest zoom (31 vs 345 requests)
- Lossless WebP: High quality compression without artifacts
- Database Storage: All tiles served directly from SQLite BLOBs (no file I/O)
- CRS.Simple: Avoids expensive geographic coordinate projections
- Total Storage: ~111 MB for all zoom levels combined
Load Performance Comparison
| Zoom Level | Merge Factor | Tiles Loaded | HTTP Requests Saved |
|---|---|---|---|
| 0 (zoomed out) | 4×4 | 31 | 91% fewer requests |
| 1 (medium) | 2×2 | 105 | 70% fewer requests |
| 2 (zoomed in) | 1×1 | 345 | baseline |
Troubleshooting
Tiles not loading:
- Verify database path is correct
- Check that
minimap_tilestable is populated - Look for errors in server console output
Map appears blank:
- Check browser console for JavaScript errors
- Verify
/api/boundsreturns valid coordinates - Ensure tiles exist for the displayed coordinate range
Performance issues:
- Try running in release mode:
cargo run --release - Check database is on fast storage (SSD)
- Reduce browser zoom level to load lower-resolution tiles