Phase 17: map & fog VTT overhaul + player-facing projection
- Pure geometry library src/lib/map/* (grid, distance 5e/pf2e/euclid, AoE circle/cone/line/square, polygon rasterize + point-in-polygon, brush, fog set algebra, player projection) with unit tests. - Schema: map tokens gain size/kind/characterId/hp/conditions/gmOnly; maps gain drawings/gridUnit(feet)/gridType/fogVersion + point/drawing sub-schemas. Dexie v8 additive migration; mapsRepo.get + transactional mutate. - Editor split into a shared MapCanvas renderer + MapEditor tool state machine: fog via brush/rectangle/polygon (+ size, reveal-all/hide-all), measurement (system-aware distance in feet), AoE templates (circle/cone/line/square preview), drawing annotations (freehand/line/arrow/rect/circle/text, GM-only), pings, and richer tokens (NxN size, character link with live HP ring, condition dots, edit popover). - Player-facing projection: toPlayerProjection strips GM-only content; PlayerMapView renders it read-only with opaque fog; uiStore.activeMapId + 'Show to players'; the player view now shows the live battle map. enemyStatus extracted to src/lib/combat/playerProjection.ts (reused, and for Phase 18). 9 geometry unit tests; maps e2e covers upload→token→reveal-all→player projection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-8
@@ -9,24 +9,30 @@ test.beforeEach(async ({ page }) => {
|
||||
await page.reload();
|
||||
});
|
||||
|
||||
test('maps: upload, place a token, toggle fog', async ({ page }) => {
|
||||
test('maps: upload, place token, reveal all, show to players', async ({ page }) => {
|
||||
await page.getByRole('button', { name: '+ New campaign' }).first().click();
|
||||
await page.locator('input[data-autofocus]').fill('VTT');
|
||||
await page.getByRole('button', { name: 'Create' }).click();
|
||||
await page.getByRole('link', { name: 'Dashboard' }).click();
|
||||
await page.getByRole('link', { name: 'Maps' }).click();
|
||||
|
||||
// Upload an image into the hidden file input
|
||||
await page.locator('input[type="file"]').setInputFiles('public/pwa-512x512.png');
|
||||
|
||||
// Editor loads (Move tool button present)
|
||||
await expect(page.getByRole('button', { name: 'Move' })).toBeVisible();
|
||||
// Editor loads (Move tool present)
|
||||
await expect(page.getByRole('button', { name: 'move', exact: true })).toBeVisible();
|
||||
|
||||
// Add a token
|
||||
await page.getByRole('button', { name: '+ Token' }).click();
|
||||
await expect(page.getByTitle(/double-click to remove/)).toBeVisible();
|
||||
await expect(page.getByTestId('map-token')).toHaveCount(1);
|
||||
|
||||
// Toggle fog on (no crash)
|
||||
await page.getByText('Fog', { exact: true }).locator('input').check();
|
||||
await expect(page.getByRole('button', { name: 'Reveal all' })).toBeVisible();
|
||||
// Reveal tool exposes the contextual fog controls; reveal all
|
||||
await page.getByRole('button', { name: 'reveal', exact: true }).click();
|
||||
await page.getByText('Fog', { exact: true }).locator('input[type=checkbox]').check();
|
||||
await page.getByRole('button', { name: 'Reveal all' }).click();
|
||||
|
||||
// Show to players, then the player view renders the battle map
|
||||
await page.getByRole('button', { name: 'Show to players' }).click();
|
||||
await page.getByRole('link', { name: 'Open player view ↗' }).click();
|
||||
await expect(page.getByRole('heading', { name: 'Battle map' })).toBeVisible();
|
||||
await expect(page.getByTestId('map-token')).toHaveCount(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user