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:
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"format": 0.3,
|
||||
"resolution": { "map_origin": { "x": 0, "y": 0 }, "map_size": { "x": 4, "y": 3 }, "pixels_per_grid": 100 },
|
||||
"line_of_sight": [[{ "x": 1, "y": 1 }, { "x": 3, "y": 1 }, { "x": 3, "y": 2 }]],
|
||||
"portals": [{ "position": { "x": 3, "y": 1.5 }, "bounds": [{ "x": 3, "y": 1 }, { "x": 3, "y": 2 }], "closed": true }],
|
||||
"lights": [{ "position": { "x": 2, "y": 2 }, "range": 4, "color": "ffd9a0", "intensity": 0.6 }],
|
||||
"image": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
|
||||
}
|
||||
@@ -38,6 +38,21 @@ test('maps: upload, place token, reveal all, show to players', async ({ page })
|
||||
await expect(page.getByTestId('map-token')).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('maps: import a Universal VTT (.dd2vtt) map', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '+ New campaign' }).first().click();
|
||||
await page.locator('input[data-autofocus]').fill('VTTimport');
|
||||
await page.getByRole('button', { name: 'Create' }).click();
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Maps' }).click();
|
||||
|
||||
await page.locator('input[type="file"]').setInputFiles('e2e/fixtures/sample.dd2vtt');
|
||||
|
||||
// Imported map opens in the editor with the file's pixels_per_grid as the grid size.
|
||||
await expect(page.getByTestId('map-viewport')).toBeVisible();
|
||||
await expect(page.getByLabel('Grid cell size')).toHaveValue('100');
|
||||
await expect(page.getByRole('button', { name: 'Export .uvtt' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('maps: zoom controls scale the canvas and fit resets', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '+ New campaign' }).first().click();
|
||||
await page.locator('input[data-autofocus]').fill('Zoom');
|
||||
|
||||
Reference in New Issue
Block a user