@fieldnotes/core 0.66.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +742 -706
- package/dist/index.cjs +385 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -9
- package/dist/index.d.ts +57 -9
- package/dist/index.js +384 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -126,6 +126,7 @@ __export(index_exports, {
|
|
|
126
126
|
isPingPresence: () => isPingPresence,
|
|
127
127
|
pathDistanceCells: () => pathDistanceCells,
|
|
128
128
|
recommendedFogCellSize: () => recommendedFogCellSize,
|
|
129
|
+
resolveFogStyle: () => resolveFogStyle,
|
|
129
130
|
resolveHtmlRouting: () => resolveHtmlRouting,
|
|
130
131
|
setFontSize: () => setFontSize,
|
|
131
132
|
smartSnap: () => smartSnap,
|
|
@@ -7325,19 +7326,181 @@ async function renderHtmlElements(elements, options) {
|
|
|
7325
7326
|
return sources;
|
|
7326
7327
|
}
|
|
7327
7328
|
|
|
7329
|
+
// src/fog/fog-style.ts
|
|
7330
|
+
var DEFAULT_PROCEDURAL_OPACITY = 0.6;
|
|
7331
|
+
var DEFAULT_PROCEDURAL_SCALE = 256;
|
|
7332
|
+
var DEFAULT_PROCEDURAL_SEED = 0;
|
|
7333
|
+
var DEFAULT_PROCEDURAL_DETAIL = 2;
|
|
7334
|
+
var DEFAULT_PROCEDURAL_TINT = "#ffffff";
|
|
7335
|
+
var MIN_SCALE = 64;
|
|
7336
|
+
var MAX_SCALE = 1024;
|
|
7337
|
+
var MIN_DETAIL = 1;
|
|
7338
|
+
var MAX_DETAIL = 4;
|
|
7339
|
+
var MAX_SEED = 65535;
|
|
7340
|
+
function clamp(value, min, max) {
|
|
7341
|
+
return Math.max(min, Math.min(max, value));
|
|
7342
|
+
}
|
|
7343
|
+
function finiteOrDefault(value, defaultValue) {
|
|
7344
|
+
return value !== void 0 && Number.isFinite(value) ? value : defaultValue;
|
|
7345
|
+
}
|
|
7346
|
+
function resolveFogStyle(style, legacyColor, defaultColor) {
|
|
7347
|
+
if (style && style.kind === "procedural") {
|
|
7348
|
+
const opacity = clamp(finiteOrDefault(style.opacity, DEFAULT_PROCEDURAL_OPACITY), 0, 1);
|
|
7349
|
+
const scale = clamp(
|
|
7350
|
+
finiteOrDefault(style.scale, DEFAULT_PROCEDURAL_SCALE),
|
|
7351
|
+
MIN_SCALE,
|
|
7352
|
+
MAX_SCALE
|
|
7353
|
+
);
|
|
7354
|
+
const seed = clamp(
|
|
7355
|
+
Math.floor(finiteOrDefault(style.seed, DEFAULT_PROCEDURAL_SEED)),
|
|
7356
|
+
0,
|
|
7357
|
+
MAX_SEED
|
|
7358
|
+
);
|
|
7359
|
+
const detail = clamp(
|
|
7360
|
+
Math.floor(finiteOrDefault(style.detail, DEFAULT_PROCEDURAL_DETAIL)),
|
|
7361
|
+
MIN_DETAIL,
|
|
7362
|
+
MAX_DETAIL
|
|
7363
|
+
);
|
|
7364
|
+
return {
|
|
7365
|
+
kind: "procedural",
|
|
7366
|
+
backdrop: style.backdrop,
|
|
7367
|
+
// `tint` is required for typed callers. Keep a visible runtime fallback for
|
|
7368
|
+
// untyped/older JavaScript hosts instead of producing a flat same-color overlay.
|
|
7369
|
+
tint: style.tint || DEFAULT_PROCEDURAL_TINT,
|
|
7370
|
+
opacity,
|
|
7371
|
+
scale,
|
|
7372
|
+
seed,
|
|
7373
|
+
detail
|
|
7374
|
+
};
|
|
7375
|
+
}
|
|
7376
|
+
if (style && (!style.kind || style.kind === "solid")) {
|
|
7377
|
+
return { kind: "solid", color: style.color };
|
|
7378
|
+
}
|
|
7379
|
+
return { kind: "solid", color: legacyColor ?? defaultColor };
|
|
7380
|
+
}
|
|
7381
|
+
|
|
7382
|
+
// src/fog/fog-procedural-tile.ts
|
|
7383
|
+
var TILE_PX = 128;
|
|
7384
|
+
function xorshift32(state) {
|
|
7385
|
+
state ^= state << 13;
|
|
7386
|
+
state ^= state >>> 17;
|
|
7387
|
+
state ^= state << 5;
|
|
7388
|
+
return state >>> 0;
|
|
7389
|
+
}
|
|
7390
|
+
function seedState(seed) {
|
|
7391
|
+
return seed * 2654435761 + 1 >>> 0 || 1;
|
|
7392
|
+
}
|
|
7393
|
+
function smoothstep(t) {
|
|
7394
|
+
return t * t * (3 - 2 * t);
|
|
7395
|
+
}
|
|
7396
|
+
function lerp(a, b, t) {
|
|
7397
|
+
return a + (b - a) * t;
|
|
7398
|
+
}
|
|
7399
|
+
function generateGradients(size, prngState) {
|
|
7400
|
+
const count = size * size;
|
|
7401
|
+
const gx = new Float32Array(count);
|
|
7402
|
+
const gy = new Float32Array(count);
|
|
7403
|
+
let s = prngState;
|
|
7404
|
+
for (let i = 0; i < count; i++) {
|
|
7405
|
+
s = xorshift32(s);
|
|
7406
|
+
const angle = (s >>> 0) / 4294967296 * Math.PI * 2;
|
|
7407
|
+
gx[i] = Math.cos(angle);
|
|
7408
|
+
gy[i] = Math.sin(angle);
|
|
7409
|
+
}
|
|
7410
|
+
return { gx, gy, state: s };
|
|
7411
|
+
}
|
|
7412
|
+
function perlinNoise(px, py, gridSize, gx, gy) {
|
|
7413
|
+
const gx0 = Math.floor(px) % gridSize;
|
|
7414
|
+
const gy0 = Math.floor(py) % gridSize;
|
|
7415
|
+
const gx1 = (gx0 + 1) % gridSize;
|
|
7416
|
+
const gy1 = (gy0 + 1) % gridSize;
|
|
7417
|
+
const fx = px - Math.floor(px);
|
|
7418
|
+
const fy = py - Math.floor(py);
|
|
7419
|
+
const sx = smoothstep(fx);
|
|
7420
|
+
const sy = smoothstep(fy);
|
|
7421
|
+
const dot = (ix, iy, dx, dy) => {
|
|
7422
|
+
const idx = iy * gridSize + ix;
|
|
7423
|
+
return gx[idx] * dx + gy[idx] * dy;
|
|
7424
|
+
};
|
|
7425
|
+
const n00 = dot(gx0, gy0, fx, fy);
|
|
7426
|
+
const n10 = dot(gx1, gy0, fx - 1, fy);
|
|
7427
|
+
const n01 = dot(gx0, gy1, fx, fy - 1);
|
|
7428
|
+
const n11 = dot(gx1, gy1, fx - 1, fy - 1);
|
|
7429
|
+
return lerp(lerp(n00, n10, sx), lerp(n01, n11, sx), sy);
|
|
7430
|
+
}
|
|
7431
|
+
function layeredNoise(x, y, octaves, gridSize, gx, gy) {
|
|
7432
|
+
let value = 0;
|
|
7433
|
+
let amplitude = 1;
|
|
7434
|
+
let frequency = 1;
|
|
7435
|
+
let maxAmplitude = 0;
|
|
7436
|
+
for (let o = 0; o < octaves; o++) {
|
|
7437
|
+
value += perlinNoise(x * frequency, y * frequency, gridSize * frequency, gx, gy) * amplitude;
|
|
7438
|
+
maxAmplitude += amplitude;
|
|
7439
|
+
amplitude *= 0.5;
|
|
7440
|
+
frequency *= 2;
|
|
7441
|
+
}
|
|
7442
|
+
return (value / maxAmplitude + 1) * 0.5;
|
|
7443
|
+
}
|
|
7444
|
+
function generateProceduralTile(style) {
|
|
7445
|
+
const gridSize = 8;
|
|
7446
|
+
const maxFreq = gridSize * (1 << style.detail - 1);
|
|
7447
|
+
const { gx, gy } = generateGradients(maxFreq, seedState(style.seed));
|
|
7448
|
+
const data = new Uint8ClampedArray(TILE_PX * TILE_PX * 4);
|
|
7449
|
+
for (let py = 0; py < TILE_PX; py++) {
|
|
7450
|
+
for (let px = 0; px < TILE_PX; px++) {
|
|
7451
|
+
const nx = px / TILE_PX * gridSize;
|
|
7452
|
+
const ny = py / TILE_PX * gridSize;
|
|
7453
|
+
const n2 = layeredNoise(nx, ny, style.detail, gridSize, gx, gy);
|
|
7454
|
+
const alpha = Math.round(n2 * style.opacity * 255);
|
|
7455
|
+
const idx = (py * TILE_PX + px) * 4;
|
|
7456
|
+
data[idx] = 255;
|
|
7457
|
+
data[idx + 1] = 255;
|
|
7458
|
+
data[idx + 2] = 255;
|
|
7459
|
+
data[idx + 3] = alpha;
|
|
7460
|
+
}
|
|
7461
|
+
}
|
|
7462
|
+
return { data, width: TILE_PX, height: TILE_PX };
|
|
7463
|
+
}
|
|
7464
|
+
var tileCache = /* @__PURE__ */ new Map();
|
|
7465
|
+
var MAX_CACHED_TILES = 16;
|
|
7466
|
+
function getCachedProceduralTile(style) {
|
|
7467
|
+
const key = `${style.opacity}\0${style.seed}\0${style.detail}`;
|
|
7468
|
+
const cached = tileCache.get(key);
|
|
7469
|
+
if (cached) return cached;
|
|
7470
|
+
const tile = generateProceduralTile(style);
|
|
7471
|
+
if (tileCache.size >= MAX_CACHED_TILES) {
|
|
7472
|
+
const oldest = tileCache.keys().next().value;
|
|
7473
|
+
if (oldest !== void 0) tileCache.delete(oldest);
|
|
7474
|
+
}
|
|
7475
|
+
tileCache.set(key, tile);
|
|
7476
|
+
return tile;
|
|
7477
|
+
}
|
|
7478
|
+
function clearProceduralTileCache() {
|
|
7479
|
+
tileCache.clear();
|
|
7480
|
+
}
|
|
7481
|
+
|
|
7328
7482
|
// src/fog/fog-renderer.ts
|
|
7329
7483
|
var DEFAULT_EDITOR_COLOR = "rgba(30, 40, 60, 0.45)";
|
|
7330
7484
|
var DEFAULT_PLAYER_COLOR = "#0b1020";
|
|
7331
7485
|
var FogRenderer = class {
|
|
7332
7486
|
tileCache = /* @__PURE__ */ new Map();
|
|
7487
|
+
patternCache = /* @__PURE__ */ new Map();
|
|
7333
7488
|
state = null;
|
|
7334
7489
|
viewMode = "off";
|
|
7335
7490
|
dirty = true;
|
|
7336
|
-
|
|
7337
|
-
|
|
7491
|
+
editorStyle;
|
|
7492
|
+
playerStyle;
|
|
7338
7493
|
constructor(options = {}) {
|
|
7339
|
-
this.
|
|
7340
|
-
|
|
7494
|
+
this.editorStyle = resolveFogStyle(
|
|
7495
|
+
options.editorStyle,
|
|
7496
|
+
options.editorColor,
|
|
7497
|
+
DEFAULT_EDITOR_COLOR
|
|
7498
|
+
);
|
|
7499
|
+
this.playerStyle = resolveFogStyle(
|
|
7500
|
+
options.playerStyle,
|
|
7501
|
+
options.playerColor,
|
|
7502
|
+
DEFAULT_PLAYER_COLOR
|
|
7503
|
+
);
|
|
7341
7504
|
}
|
|
7342
7505
|
setState(state) {
|
|
7343
7506
|
this.state = state;
|
|
@@ -7363,12 +7526,23 @@ var FogRenderer = class {
|
|
|
7363
7526
|
isVisible() {
|
|
7364
7527
|
return this.viewMode !== "off" && this.state !== null;
|
|
7365
7528
|
}
|
|
7529
|
+
getResolvedStyle(mode) {
|
|
7530
|
+
return mode === "editor" ? this.editorStyle : this.playerStyle;
|
|
7531
|
+
}
|
|
7366
7532
|
render(ctx, camera, viewportWidth, viewportHeight, _dpr) {
|
|
7367
7533
|
if (!this.state || this.viewMode === "off") return;
|
|
7368
7534
|
const def = this.state.definition;
|
|
7369
7535
|
const cellSize = def.cellSize;
|
|
7370
7536
|
const tileWorldSize = FOG_TILE_CELLS * cellSize;
|
|
7371
|
-
const
|
|
7537
|
+
const mode = this.viewMode === "editor" ? "editor" : "player";
|
|
7538
|
+
const style = this.getResolvedStyle(mode);
|
|
7539
|
+
const proceduralStyle = style.kind === "procedural" ? style : null;
|
|
7540
|
+
const color = style.kind === "procedural" ? normalizeCanvasColor(
|
|
7541
|
+
ctx,
|
|
7542
|
+
style.backdrop,
|
|
7543
|
+
mode === "player" ? DEFAULT_PLAYER_COLOR : DEFAULT_EDITOR_COLOR
|
|
7544
|
+
) : style.color;
|
|
7545
|
+
const safetyColor = proceduralStyle && mode === "player" ? DEFAULT_PLAYER_COLOR : null;
|
|
7372
7546
|
const worldBounds = getVisibleWorld(camera, viewportWidth, viewportHeight);
|
|
7373
7547
|
const minTX = Math.floor(Math.max(def.bounds.x, worldBounds.x) / tileWorldSize);
|
|
7374
7548
|
const minTY = Math.floor(Math.max(def.bounds.y, worldBounds.y) / tileWorldSize);
|
|
@@ -7399,7 +7573,22 @@ var FogRenderer = class {
|
|
|
7399
7573
|
const clipR = Math.min(tileWorldX + tileWorldSize, def.bounds.x + def.bounds.w);
|
|
7400
7574
|
const clipB = Math.min(tileWorldY + tileWorldSize, def.bounds.y + def.bounds.h);
|
|
7401
7575
|
if (clipR > clipX && clipB > clipY) {
|
|
7576
|
+
if (safetyColor) {
|
|
7577
|
+
ctx.fillStyle = safetyColor;
|
|
7578
|
+
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7579
|
+
}
|
|
7580
|
+
ctx.fillStyle = color;
|
|
7402
7581
|
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7582
|
+
if (proceduralStyle) {
|
|
7583
|
+
this.paintProceduralOverlay(
|
|
7584
|
+
ctx,
|
|
7585
|
+
proceduralStyle,
|
|
7586
|
+
clipX,
|
|
7587
|
+
clipY,
|
|
7588
|
+
clipR - clipX,
|
|
7589
|
+
clipB - clipY
|
|
7590
|
+
);
|
|
7591
|
+
}
|
|
7403
7592
|
}
|
|
7404
7593
|
continue;
|
|
7405
7594
|
}
|
|
@@ -7407,18 +7596,33 @@ var FogRenderer = class {
|
|
|
7407
7596
|
continue;
|
|
7408
7597
|
}
|
|
7409
7598
|
if (data) {
|
|
7599
|
+
if (safetyColor) this.renderTile(ctx, data, tx, ty, def, safetyColor);
|
|
7410
7600
|
this.renderTile(ctx, data, tx, ty, def, color);
|
|
7601
|
+
if (proceduralStyle) {
|
|
7602
|
+
this.renderTileProceduralOverlay(ctx, data, tx, ty, def, proceduralStyle);
|
|
7603
|
+
}
|
|
7411
7604
|
}
|
|
7412
7605
|
}
|
|
7413
7606
|
}
|
|
7414
7607
|
ctx.restore();
|
|
7415
7608
|
this.dirty = false;
|
|
7416
7609
|
}
|
|
7417
|
-
renderForExport(ctx, state, mode, color) {
|
|
7610
|
+
renderForExport(ctx, state, mode, color, style) {
|
|
7418
7611
|
const def = state.definition;
|
|
7419
7612
|
const cellSize = def.cellSize;
|
|
7420
7613
|
const tileWorldSize = FOG_TILE_CELLS * cellSize;
|
|
7421
|
-
const
|
|
7614
|
+
const resolved = style ? resolveFogStyle(
|
|
7615
|
+
style,
|
|
7616
|
+
void 0,
|
|
7617
|
+
mode === "editor" ? DEFAULT_EDITOR_COLOR : DEFAULT_PLAYER_COLOR
|
|
7618
|
+
) : this.getResolvedStyle(mode);
|
|
7619
|
+
const proceduralStyle = !color && resolved.kind === "procedural" ? resolved : null;
|
|
7620
|
+
const fogColor = color ?? (proceduralStyle ? normalizeCanvasColor(
|
|
7621
|
+
ctx,
|
|
7622
|
+
proceduralStyle.backdrop,
|
|
7623
|
+
mode === "player" ? DEFAULT_PLAYER_COLOR : DEFAULT_EDITOR_COLOR
|
|
7624
|
+
) : resolved.kind === "solid" ? resolved.color : resolved.backdrop);
|
|
7625
|
+
const safetyColor = proceduralStyle && mode === "player" ? DEFAULT_PLAYER_COLOR : null;
|
|
7422
7626
|
const baseCovered = def.base === "covered";
|
|
7423
7627
|
const tileMap = /* @__PURE__ */ new Map();
|
|
7424
7628
|
for (const tile of state.tiles) {
|
|
@@ -7441,20 +7645,129 @@ var FogRenderer = class {
|
|
|
7441
7645
|
const clipR = Math.min(tileWorldX + tileWorldSize, def.bounds.x + def.bounds.w);
|
|
7442
7646
|
const clipB = Math.min(tileWorldY + tileWorldSize, def.bounds.y + def.bounds.h);
|
|
7443
7647
|
if (clipR > clipX && clipB > clipY) {
|
|
7648
|
+
if (safetyColor) {
|
|
7649
|
+
ctx.fillStyle = safetyColor;
|
|
7650
|
+
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7651
|
+
}
|
|
7652
|
+
ctx.fillStyle = fogColor;
|
|
7444
7653
|
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7654
|
+
if (proceduralStyle) {
|
|
7655
|
+
this.paintProceduralOverlay(
|
|
7656
|
+
ctx,
|
|
7657
|
+
proceduralStyle,
|
|
7658
|
+
clipX,
|
|
7659
|
+
clipY,
|
|
7660
|
+
clipR - clipX,
|
|
7661
|
+
clipB - clipY
|
|
7662
|
+
);
|
|
7663
|
+
}
|
|
7445
7664
|
}
|
|
7446
7665
|
continue;
|
|
7447
7666
|
}
|
|
7448
7667
|
if (data) {
|
|
7668
|
+
if (safetyColor) this.renderTileForExport(ctx, data, tx, ty, def, safetyColor);
|
|
7449
7669
|
this.renderTileForExport(ctx, data, tx, ty, def, fogColor);
|
|
7670
|
+
if (proceduralStyle) {
|
|
7671
|
+
this.renderTileProceduralOverlay(ctx, data, tx, ty, def, proceduralStyle);
|
|
7672
|
+
}
|
|
7450
7673
|
}
|
|
7451
7674
|
}
|
|
7452
7675
|
}
|
|
7453
7676
|
}
|
|
7454
7677
|
dispose() {
|
|
7455
7678
|
this.tileCache.clear();
|
|
7679
|
+
this.patternCache.clear();
|
|
7680
|
+
clearProceduralTileCache();
|
|
7456
7681
|
this.state = null;
|
|
7457
7682
|
}
|
|
7683
|
+
getOrCreatePattern(ctx, style, worldScale) {
|
|
7684
|
+
const key = `${style.backdrop}\0${style.tint}\0${style.opacity}\0${style.scale}\0${style.seed}\0${style.detail}\0${worldScale}`;
|
|
7685
|
+
const cached = this.patternCache.get(key);
|
|
7686
|
+
if (cached !== void 0) return cached;
|
|
7687
|
+
let pattern = null;
|
|
7688
|
+
try {
|
|
7689
|
+
const tileData = getCachedProceduralTile(style);
|
|
7690
|
+
pattern = this.createPatternFromTileData(ctx, tileData, style, worldScale);
|
|
7691
|
+
} catch {
|
|
7692
|
+
}
|
|
7693
|
+
if (this.patternCache.size >= 32) {
|
|
7694
|
+
const oldest = this.patternCache.keys().next().value;
|
|
7695
|
+
if (oldest !== void 0) this.patternCache.delete(oldest);
|
|
7696
|
+
}
|
|
7697
|
+
this.patternCache.set(key, pattern);
|
|
7698
|
+
return pattern;
|
|
7699
|
+
}
|
|
7700
|
+
createPatternFromTileData(ctx, tileData, style, worldScale) {
|
|
7701
|
+
if (typeof document === "undefined") return null;
|
|
7702
|
+
const sourceCanvas = document.createElement("canvas");
|
|
7703
|
+
sourceCanvas.width = tileData.width;
|
|
7704
|
+
sourceCanvas.height = tileData.height;
|
|
7705
|
+
const sourceCtx = sourceCanvas.getContext("2d");
|
|
7706
|
+
if (!sourceCtx) return null;
|
|
7707
|
+
const imageData = new ImageData(
|
|
7708
|
+
new Uint8ClampedArray(tileData.data),
|
|
7709
|
+
tileData.width,
|
|
7710
|
+
tileData.height
|
|
7711
|
+
);
|
|
7712
|
+
sourceCtx.putImageData(imageData, 0, 0);
|
|
7713
|
+
sourceCtx.globalCompositeOperation = "source-in";
|
|
7714
|
+
sourceCtx.fillStyle = normalizeCanvasColor(sourceCtx, style.tint, "#ffffff");
|
|
7715
|
+
sourceCtx.fillRect(0, 0, tileData.width, tileData.height);
|
|
7716
|
+
sourceCtx.globalCompositeOperation = "source-over";
|
|
7717
|
+
const patternScale = style.scale * worldScale / tileData.width;
|
|
7718
|
+
const pattern = ctx.createPattern(sourceCanvas, "repeat");
|
|
7719
|
+
if (pattern && typeof pattern.setTransform === "function" && typeof DOMMatrix !== "undefined") {
|
|
7720
|
+
try {
|
|
7721
|
+
pattern.setTransform(new DOMMatrix([patternScale, 0, 0, patternScale, 0, 0]));
|
|
7722
|
+
return pattern;
|
|
7723
|
+
} catch {
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
const patternPx = Math.round(style.scale * worldScale);
|
|
7727
|
+
if (patternPx < 1) return null;
|
|
7728
|
+
const patternCanvas = document.createElement("canvas");
|
|
7729
|
+
patternCanvas.width = patternPx;
|
|
7730
|
+
patternCanvas.height = patternPx;
|
|
7731
|
+
const patternCtx = patternCanvas.getContext("2d");
|
|
7732
|
+
if (!patternCtx) return null;
|
|
7733
|
+
patternCtx.drawImage(sourceCanvas, 0, 0, patternPx, patternPx);
|
|
7734
|
+
return ctx.createPattern(patternCanvas, "repeat");
|
|
7735
|
+
}
|
|
7736
|
+
paintProceduralOverlay(ctx, style, x, y, w, h) {
|
|
7737
|
+
const pattern = this.getOrCreatePattern(ctx, style, 1);
|
|
7738
|
+
if (!pattern) return;
|
|
7739
|
+
ctx.save();
|
|
7740
|
+
ctx.fillStyle = pattern;
|
|
7741
|
+
ctx.fillRect(x, y, w, h);
|
|
7742
|
+
ctx.restore();
|
|
7743
|
+
}
|
|
7744
|
+
renderTileProceduralOverlay(ctx, data, tx, ty, def, style) {
|
|
7745
|
+
const cellSize = def.cellSize;
|
|
7746
|
+
const tileWorldX = tx * FOG_TILE_CELLS * cellSize;
|
|
7747
|
+
const tileWorldY = ty * FOG_TILE_CELLS * cellSize;
|
|
7748
|
+
const pattern = this.getOrCreatePattern(ctx, style, 1);
|
|
7749
|
+
if (!pattern) return;
|
|
7750
|
+
const bytes = decodeBase64(data);
|
|
7751
|
+
ctx.save();
|
|
7752
|
+
ctx.fillStyle = pattern;
|
|
7753
|
+
for (let row = 0; row < FOG_TILE_CELLS; row++) {
|
|
7754
|
+
for (let col = 0; col < FOG_TILE_CELLS; col++) {
|
|
7755
|
+
const cellWorldX = tileWorldX + col * cellSize;
|
|
7756
|
+
const cellWorldY = tileWorldY + row * cellSize;
|
|
7757
|
+
if (cellWorldX < def.bounds.x || cellWorldY < def.bounds.y || cellWorldX >= def.bounds.x + def.bounds.w || cellWorldY >= def.bounds.y + def.bounds.h) {
|
|
7758
|
+
continue;
|
|
7759
|
+
}
|
|
7760
|
+
const index = row * FOG_TILE_CELLS + col;
|
|
7761
|
+
const byteIndex = index >> 3;
|
|
7762
|
+
const bitIndex = 7 - (index & 7);
|
|
7763
|
+
const revealed = (bytes[byteIndex] >> bitIndex & 1) === 1;
|
|
7764
|
+
if (!revealed) {
|
|
7765
|
+
ctx.fillRect(cellWorldX, cellWorldY, cellSize, cellSize);
|
|
7766
|
+
}
|
|
7767
|
+
}
|
|
7768
|
+
}
|
|
7769
|
+
ctx.restore();
|
|
7770
|
+
}
|
|
7458
7771
|
tileRaster(data, color) {
|
|
7459
7772
|
const key = `${color}\0${data}`;
|
|
7460
7773
|
const cached = this.tileCache.get(key);
|
|
@@ -7538,6 +7851,22 @@ function getVisibleWorld(camera, viewportWidth, viewportHeight) {
|
|
|
7538
7851
|
h: bottomRight.y - topLeft.y
|
|
7539
7852
|
};
|
|
7540
7853
|
}
|
|
7854
|
+
function normalizeCanvasColor(ctx, value, fallback) {
|
|
7855
|
+
const previous = ctx.fillStyle;
|
|
7856
|
+
try {
|
|
7857
|
+
ctx.fillStyle = "#010203";
|
|
7858
|
+
ctx.fillStyle = value;
|
|
7859
|
+
const first = ctx.fillStyle;
|
|
7860
|
+
ctx.fillStyle = "#040506";
|
|
7861
|
+
ctx.fillStyle = value;
|
|
7862
|
+
const second = ctx.fillStyle;
|
|
7863
|
+
return typeof first === "string" && first === second ? first : fallback;
|
|
7864
|
+
} catch {
|
|
7865
|
+
return fallback;
|
|
7866
|
+
} finally {
|
|
7867
|
+
ctx.fillStyle = previous;
|
|
7868
|
+
}
|
|
7869
|
+
}
|
|
7541
7870
|
|
|
7542
7871
|
// src/canvas/export-image.ts
|
|
7543
7872
|
var DEFAULT_IMAGE_TIMEOUT_MS = 1e4;
|
|
@@ -7953,7 +8282,13 @@ async function exportImage(store, options = {}, layerManager) {
|
|
|
7953
8282
|
}
|
|
7954
8283
|
if (options.fog) {
|
|
7955
8284
|
const fogRenderer = new FogRenderer();
|
|
7956
|
-
fogRenderer.renderForExport(
|
|
8285
|
+
fogRenderer.renderForExport(
|
|
8286
|
+
ctx,
|
|
8287
|
+
options.fog.state,
|
|
8288
|
+
options.fog.mode,
|
|
8289
|
+
options.fog.color,
|
|
8290
|
+
options.fog.style
|
|
8291
|
+
);
|
|
7957
8292
|
}
|
|
7958
8293
|
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
7959
8294
|
return new Promise((resolve) => {
|
|
@@ -8347,7 +8682,13 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
8347
8682
|
if (fogCtx) {
|
|
8348
8683
|
fogCtx.translate(-bounds.x, -bounds.y);
|
|
8349
8684
|
const fogRenderer = new FogRenderer();
|
|
8350
|
-
fogRenderer.renderForExport(
|
|
8685
|
+
fogRenderer.renderForExport(
|
|
8686
|
+
fogCtx,
|
|
8687
|
+
fogState,
|
|
8688
|
+
options.fog.mode,
|
|
8689
|
+
options.fog.color,
|
|
8690
|
+
options.fog.style
|
|
8691
|
+
);
|
|
8351
8692
|
try {
|
|
8352
8693
|
const fogDataUri = fogCanvas.toDataURL("image/png");
|
|
8353
8694
|
if (fogDataUri.startsWith("data:")) {
|
|
@@ -11342,26 +11683,35 @@ var Viewport = class _Viewport {
|
|
|
11342
11683
|
const expected = base.expectedCanvasTypes ? /* @__PURE__ */ new Set([...declared, ...base.expectedCanvasTypes]) : declared;
|
|
11343
11684
|
return { ...base, htmlPainters: registry, expectedCanvasTypes: expected };
|
|
11344
11685
|
}
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11686
|
+
/**
|
|
11687
|
+
* Carry constructor-configured fog presentation into both implicit exports and
|
|
11688
|
+
* explicit state/mode exports. Explicit style and legacy color overrides win.
|
|
11689
|
+
*/
|
|
11690
|
+
withFogDefaults(options) {
|
|
11691
|
+
const fog = options.fog;
|
|
11692
|
+
if (fog === false) return options;
|
|
11693
|
+
if (fog !== void 0) {
|
|
11694
|
+
if (fog.style !== void 0 || fog.color !== void 0) return options;
|
|
11695
|
+
return {
|
|
11696
|
+
...options,
|
|
11697
|
+
fog: { ...fog, style: this.fogRenderer.getResolvedStyle(fog.mode) }
|
|
11698
|
+
};
|
|
11353
11699
|
}
|
|
11700
|
+
if (!this.fogRenderer.isVisible()) return options;
|
|
11701
|
+
const state = this.fogManager.getState();
|
|
11702
|
+
if (!state) return options;
|
|
11703
|
+
const mode = this.fogRenderer.getViewMode();
|
|
11704
|
+
return {
|
|
11705
|
+
...options,
|
|
11706
|
+
fog: { state, mode, style: this.fogRenderer.getResolvedStyle(mode) }
|
|
11707
|
+
};
|
|
11708
|
+
}
|
|
11709
|
+
async exportImage(options) {
|
|
11710
|
+
const opts = this.withFogDefaults(this.withHtmlDefaults(options));
|
|
11354
11711
|
return exportImage(this.store, opts, this.layerManager);
|
|
11355
11712
|
}
|
|
11356
11713
|
async exportSVG(options) {
|
|
11357
|
-
const opts = this.withHtmlDefaults(options);
|
|
11358
|
-
if (opts.fog === void 0 && this.fogRenderer.isVisible()) {
|
|
11359
|
-
const state = this.fogManager.getState();
|
|
11360
|
-
if (state) {
|
|
11361
|
-
const mode = this.fogRenderer.getViewMode();
|
|
11362
|
-
opts.fog = { state, mode };
|
|
11363
|
-
}
|
|
11364
|
-
}
|
|
11714
|
+
const opts = this.withFogDefaults(this.withHtmlDefaults(options));
|
|
11365
11715
|
return exportSvg(this.store, opts, this.layerManager);
|
|
11366
11716
|
}
|
|
11367
11717
|
loadState(state) {
|
|
@@ -12995,15 +13345,15 @@ function applyCameraView(camera, view, canvasW, canvasH) {
|
|
|
12995
13345
|
var DEFAULT_DURATION_MS3 = 400;
|
|
12996
13346
|
var FRAMED_EPSILON = 1e-6;
|
|
12997
13347
|
var easeOutCubic2 = (t) => 1 - Math.pow(1 - t, 3);
|
|
12998
|
-
function
|
|
13348
|
+
function lerp2(a, b, k) {
|
|
12999
13349
|
return a + (b - a) * k;
|
|
13000
13350
|
}
|
|
13001
13351
|
function lerpView(from, to, k) {
|
|
13002
13352
|
return {
|
|
13003
|
-
x:
|
|
13004
|
-
y:
|
|
13005
|
-
w:
|
|
13006
|
-
h:
|
|
13353
|
+
x: lerp2(from.x, to.x, k),
|
|
13354
|
+
y: lerp2(from.y, to.y, k),
|
|
13355
|
+
w: lerp2(from.w, to.w, k),
|
|
13356
|
+
h: lerp2(from.h, to.h, k)
|
|
13007
13357
|
};
|
|
13008
13358
|
}
|
|
13009
13359
|
function viewsClose(a, b) {
|
|
@@ -14257,7 +14607,7 @@ var PencilTool = class {
|
|
|
14257
14607
|
};
|
|
14258
14608
|
|
|
14259
14609
|
// src/elements/stroke-erase.ts
|
|
14260
|
-
function
|
|
14610
|
+
function lerp3(a, b, t) {
|
|
14261
14611
|
return {
|
|
14262
14612
|
x: a.x + (b.x - a.x) * t,
|
|
14263
14613
|
y: a.y + (b.y - a.y) * t,
|
|
@@ -14316,13 +14666,13 @@ function erasePoints(points, eraser, radius) {
|
|
|
14316
14666
|
erased = true;
|
|
14317
14667
|
if (tLo > 0) {
|
|
14318
14668
|
if (current.length === 0) current.push(a);
|
|
14319
|
-
current.push(
|
|
14669
|
+
current.push(lerp3(a, b, tLo));
|
|
14320
14670
|
flush();
|
|
14321
14671
|
} else {
|
|
14322
14672
|
flush();
|
|
14323
14673
|
}
|
|
14324
14674
|
if (tHi < 1) {
|
|
14325
|
-
current = [
|
|
14675
|
+
current = [lerp3(a, b, tHi), b];
|
|
14326
14676
|
}
|
|
14327
14677
|
}
|
|
14328
14678
|
flush();
|
|
@@ -16838,7 +17188,7 @@ var FogTool = class {
|
|
|
16838
17188
|
};
|
|
16839
17189
|
|
|
16840
17190
|
// src/index.ts
|
|
16841
|
-
var VERSION = "0.
|
|
17191
|
+
var VERSION = "0.67.0";
|
|
16842
17192
|
// Annotate the CommonJS export names for ESM import in node:
|
|
16843
17193
|
0 && (module.exports = {
|
|
16844
17194
|
AWARENESS_MAX_SELECTION,
|
|
@@ -16947,6 +17297,7 @@ var VERSION = "0.66.0";
|
|
|
16947
17297
|
isPingPresence,
|
|
16948
17298
|
pathDistanceCells,
|
|
16949
17299
|
recommendedFogCellSize,
|
|
17300
|
+
resolveFogStyle,
|
|
16950
17301
|
resolveHtmlRouting,
|
|
16951
17302
|
setFontSize,
|
|
16952
17303
|
smartSnap,
|