Phase 3: Universal VTT (.dd2vtt/.uvtt) import + export

- src/lib/vtt/uvtt.ts: pure, tested parser converting UVTT grid-unit geometry to
  image pixels (pixels_per_grid → gridSize), extracting the base64 image, walls
  (line_of_sight), doors (portals) and lights; plus toUvtt() for export.
- BattleMap gains walls/doors/lights (Dexie v11, backfilled). mapsRepo.createFromVtt.
- MapsPage "+ Add map" now accepts .dd2vtt/.uvtt/.df2vtt (text) and images, and a
  per-map "Export .uvtt" (image dims → map_size). downloadText() helper.
- Walls render faintly for the GM (CanvasView.walls / drawScene) so imported
  line-of-sight is visible; Phase 4 will turn walls into dynamic vision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 14:51:56 +02:00
parent 1aff63f29c
commit 36f0ea66b3
12 changed files with 338 additions and 16 deletions
+10
View File
@@ -104,6 +104,16 @@ export class TtrpgDatabase extends Dexie {
// v10 — Phase 2: characters gain `portrait`, map tokens gain `image`
// (both optional data URLs). No backfill needed.
this.version(10).stores({});
// v11 — Phase 3: maps gain walls/doors/lights (UVTT import + dynamic vision).
// Backfill empty arrays so code can read them on pre-existing maps.
this.version(11).stores({}).upgrade(async (tx) => {
await tx.table('maps').toCollection().modify((m: Record<string, unknown>) => {
if (m.walls === undefined) m.walls = [];
if (m.doors === undefined) m.doors = [];
if (m.lights === undefined) m.lights = [];
});
});
}
}