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:
@@ -36,6 +36,8 @@ export interface CanvasView {
|
||||
revealed: string[];
|
||||
tokens: CanvasToken[];
|
||||
drawings: CanvasDrawing[];
|
||||
/** sight-blocking walls, drawn faintly for the GM (not sent to players) */
|
||||
walls?: { points: Point[] }[] | undefined;
|
||||
}
|
||||
|
||||
export interface Overlay {
|
||||
@@ -137,7 +139,7 @@ export function MapCanvas({ view, viewportHeight = '70vh', readOnly, playerFog,
|
||||
drawScene(canvasRef.current, imgRef.current, size.w, size.h, {
|
||||
vp, W, H, gridSize, cols, rows,
|
||||
showGrid: view.showGrid, fogEnabled: view.fogEnabled, revealed: view.revealed,
|
||||
playerFog: !!playerFog, drawings: view.drawings, overlay,
|
||||
playerFog: !!playerFog, drawings: view.drawings, overlay, walls: view.walls,
|
||||
});
|
||||
});
|
||||
return () => cancelAnimationFrame(raf);
|
||||
@@ -228,7 +230,7 @@ interface SceneParams {
|
||||
vp: Viewport;
|
||||
W: number; H: number; gridSize: number; cols: number; rows: number;
|
||||
showGrid: boolean; fogEnabled: boolean; revealed: string[]; playerFog: boolean;
|
||||
drawings: CanvasDrawing[]; overlay?: Overlay | undefined;
|
||||
drawings: CanvasDrawing[]; overlay?: Overlay | undefined; walls?: { points: Point[] }[] | undefined;
|
||||
}
|
||||
|
||||
/** Draw the whole scene at device resolution with a camera transform. */
|
||||
@@ -291,6 +293,21 @@ function drawScene(canvas: HTMLCanvasElement | null, img: HTMLImageElement | nul
|
||||
cam();
|
||||
for (const d of p.drawings) drawShape(ctx, d);
|
||||
|
||||
// Walls (GM only — faint, so imported line-of-sight is visible while editing)
|
||||
if (p.walls?.length) {
|
||||
cam();
|
||||
ctx.strokeStyle = 'rgba(80,200,255,0.6)';
|
||||
ctx.lineWidth = 2 / zoom;
|
||||
ctx.lineJoin = 'round'; ctx.lineCap = 'round';
|
||||
for (const w of p.walls) {
|
||||
if (w.points.length < 2) continue;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(w.points[0]!.x, w.points[0]!.y);
|
||||
for (const pt of w.points.slice(1)) ctx.lineTo(pt.x, pt.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay (AoE/measure/draft/poly/brush)
|
||||
const o = p.overlay;
|
||||
if (o) {
|
||||
|
||||
Reference in New Issue
Block a user