@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.js
CHANGED
|
@@ -7174,19 +7174,181 @@ async function renderHtmlElements(elements, options) {
|
|
|
7174
7174
|
return sources;
|
|
7175
7175
|
}
|
|
7176
7176
|
|
|
7177
|
+
// src/fog/fog-style.ts
|
|
7178
|
+
var DEFAULT_PROCEDURAL_OPACITY = 0.6;
|
|
7179
|
+
var DEFAULT_PROCEDURAL_SCALE = 256;
|
|
7180
|
+
var DEFAULT_PROCEDURAL_SEED = 0;
|
|
7181
|
+
var DEFAULT_PROCEDURAL_DETAIL = 2;
|
|
7182
|
+
var DEFAULT_PROCEDURAL_TINT = "#ffffff";
|
|
7183
|
+
var MIN_SCALE = 64;
|
|
7184
|
+
var MAX_SCALE = 1024;
|
|
7185
|
+
var MIN_DETAIL = 1;
|
|
7186
|
+
var MAX_DETAIL = 4;
|
|
7187
|
+
var MAX_SEED = 65535;
|
|
7188
|
+
function clamp(value, min, max) {
|
|
7189
|
+
return Math.max(min, Math.min(max, value));
|
|
7190
|
+
}
|
|
7191
|
+
function finiteOrDefault(value, defaultValue) {
|
|
7192
|
+
return value !== void 0 && Number.isFinite(value) ? value : defaultValue;
|
|
7193
|
+
}
|
|
7194
|
+
function resolveFogStyle(style, legacyColor, defaultColor) {
|
|
7195
|
+
if (style && style.kind === "procedural") {
|
|
7196
|
+
const opacity = clamp(finiteOrDefault(style.opacity, DEFAULT_PROCEDURAL_OPACITY), 0, 1);
|
|
7197
|
+
const scale = clamp(
|
|
7198
|
+
finiteOrDefault(style.scale, DEFAULT_PROCEDURAL_SCALE),
|
|
7199
|
+
MIN_SCALE,
|
|
7200
|
+
MAX_SCALE
|
|
7201
|
+
);
|
|
7202
|
+
const seed = clamp(
|
|
7203
|
+
Math.floor(finiteOrDefault(style.seed, DEFAULT_PROCEDURAL_SEED)),
|
|
7204
|
+
0,
|
|
7205
|
+
MAX_SEED
|
|
7206
|
+
);
|
|
7207
|
+
const detail = clamp(
|
|
7208
|
+
Math.floor(finiteOrDefault(style.detail, DEFAULT_PROCEDURAL_DETAIL)),
|
|
7209
|
+
MIN_DETAIL,
|
|
7210
|
+
MAX_DETAIL
|
|
7211
|
+
);
|
|
7212
|
+
return {
|
|
7213
|
+
kind: "procedural",
|
|
7214
|
+
backdrop: style.backdrop,
|
|
7215
|
+
// `tint` is required for typed callers. Keep a visible runtime fallback for
|
|
7216
|
+
// untyped/older JavaScript hosts instead of producing a flat same-color overlay.
|
|
7217
|
+
tint: style.tint || DEFAULT_PROCEDURAL_TINT,
|
|
7218
|
+
opacity,
|
|
7219
|
+
scale,
|
|
7220
|
+
seed,
|
|
7221
|
+
detail
|
|
7222
|
+
};
|
|
7223
|
+
}
|
|
7224
|
+
if (style && (!style.kind || style.kind === "solid")) {
|
|
7225
|
+
return { kind: "solid", color: style.color };
|
|
7226
|
+
}
|
|
7227
|
+
return { kind: "solid", color: legacyColor ?? defaultColor };
|
|
7228
|
+
}
|
|
7229
|
+
|
|
7230
|
+
// src/fog/fog-procedural-tile.ts
|
|
7231
|
+
var TILE_PX = 128;
|
|
7232
|
+
function xorshift32(state) {
|
|
7233
|
+
state ^= state << 13;
|
|
7234
|
+
state ^= state >>> 17;
|
|
7235
|
+
state ^= state << 5;
|
|
7236
|
+
return state >>> 0;
|
|
7237
|
+
}
|
|
7238
|
+
function seedState(seed) {
|
|
7239
|
+
return seed * 2654435761 + 1 >>> 0 || 1;
|
|
7240
|
+
}
|
|
7241
|
+
function smoothstep(t) {
|
|
7242
|
+
return t * t * (3 - 2 * t);
|
|
7243
|
+
}
|
|
7244
|
+
function lerp(a, b, t) {
|
|
7245
|
+
return a + (b - a) * t;
|
|
7246
|
+
}
|
|
7247
|
+
function generateGradients(size, prngState) {
|
|
7248
|
+
const count = size * size;
|
|
7249
|
+
const gx = new Float32Array(count);
|
|
7250
|
+
const gy = new Float32Array(count);
|
|
7251
|
+
let s = prngState;
|
|
7252
|
+
for (let i = 0; i < count; i++) {
|
|
7253
|
+
s = xorshift32(s);
|
|
7254
|
+
const angle = (s >>> 0) / 4294967296 * Math.PI * 2;
|
|
7255
|
+
gx[i] = Math.cos(angle);
|
|
7256
|
+
gy[i] = Math.sin(angle);
|
|
7257
|
+
}
|
|
7258
|
+
return { gx, gy, state: s };
|
|
7259
|
+
}
|
|
7260
|
+
function perlinNoise(px, py, gridSize, gx, gy) {
|
|
7261
|
+
const gx0 = Math.floor(px) % gridSize;
|
|
7262
|
+
const gy0 = Math.floor(py) % gridSize;
|
|
7263
|
+
const gx1 = (gx0 + 1) % gridSize;
|
|
7264
|
+
const gy1 = (gy0 + 1) % gridSize;
|
|
7265
|
+
const fx = px - Math.floor(px);
|
|
7266
|
+
const fy = py - Math.floor(py);
|
|
7267
|
+
const sx = smoothstep(fx);
|
|
7268
|
+
const sy = smoothstep(fy);
|
|
7269
|
+
const dot = (ix, iy, dx, dy) => {
|
|
7270
|
+
const idx = iy * gridSize + ix;
|
|
7271
|
+
return gx[idx] * dx + gy[idx] * dy;
|
|
7272
|
+
};
|
|
7273
|
+
const n00 = dot(gx0, gy0, fx, fy);
|
|
7274
|
+
const n10 = dot(gx1, gy0, fx - 1, fy);
|
|
7275
|
+
const n01 = dot(gx0, gy1, fx, fy - 1);
|
|
7276
|
+
const n11 = dot(gx1, gy1, fx - 1, fy - 1);
|
|
7277
|
+
return lerp(lerp(n00, n10, sx), lerp(n01, n11, sx), sy);
|
|
7278
|
+
}
|
|
7279
|
+
function layeredNoise(x, y, octaves, gridSize, gx, gy) {
|
|
7280
|
+
let value = 0;
|
|
7281
|
+
let amplitude = 1;
|
|
7282
|
+
let frequency = 1;
|
|
7283
|
+
let maxAmplitude = 0;
|
|
7284
|
+
for (let o = 0; o < octaves; o++) {
|
|
7285
|
+
value += perlinNoise(x * frequency, y * frequency, gridSize * frequency, gx, gy) * amplitude;
|
|
7286
|
+
maxAmplitude += amplitude;
|
|
7287
|
+
amplitude *= 0.5;
|
|
7288
|
+
frequency *= 2;
|
|
7289
|
+
}
|
|
7290
|
+
return (value / maxAmplitude + 1) * 0.5;
|
|
7291
|
+
}
|
|
7292
|
+
function generateProceduralTile(style) {
|
|
7293
|
+
const gridSize = 8;
|
|
7294
|
+
const maxFreq = gridSize * (1 << style.detail - 1);
|
|
7295
|
+
const { gx, gy } = generateGradients(maxFreq, seedState(style.seed));
|
|
7296
|
+
const data = new Uint8ClampedArray(TILE_PX * TILE_PX * 4);
|
|
7297
|
+
for (let py = 0; py < TILE_PX; py++) {
|
|
7298
|
+
for (let px = 0; px < TILE_PX; px++) {
|
|
7299
|
+
const nx = px / TILE_PX * gridSize;
|
|
7300
|
+
const ny = py / TILE_PX * gridSize;
|
|
7301
|
+
const n2 = layeredNoise(nx, ny, style.detail, gridSize, gx, gy);
|
|
7302
|
+
const alpha = Math.round(n2 * style.opacity * 255);
|
|
7303
|
+
const idx = (py * TILE_PX + px) * 4;
|
|
7304
|
+
data[idx] = 255;
|
|
7305
|
+
data[idx + 1] = 255;
|
|
7306
|
+
data[idx + 2] = 255;
|
|
7307
|
+
data[idx + 3] = alpha;
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
return { data, width: TILE_PX, height: TILE_PX };
|
|
7311
|
+
}
|
|
7312
|
+
var tileCache = /* @__PURE__ */ new Map();
|
|
7313
|
+
var MAX_CACHED_TILES = 16;
|
|
7314
|
+
function getCachedProceduralTile(style) {
|
|
7315
|
+
const key = `${style.opacity}\0${style.seed}\0${style.detail}`;
|
|
7316
|
+
const cached = tileCache.get(key);
|
|
7317
|
+
if (cached) return cached;
|
|
7318
|
+
const tile = generateProceduralTile(style);
|
|
7319
|
+
if (tileCache.size >= MAX_CACHED_TILES) {
|
|
7320
|
+
const oldest = tileCache.keys().next().value;
|
|
7321
|
+
if (oldest !== void 0) tileCache.delete(oldest);
|
|
7322
|
+
}
|
|
7323
|
+
tileCache.set(key, tile);
|
|
7324
|
+
return tile;
|
|
7325
|
+
}
|
|
7326
|
+
function clearProceduralTileCache() {
|
|
7327
|
+
tileCache.clear();
|
|
7328
|
+
}
|
|
7329
|
+
|
|
7177
7330
|
// src/fog/fog-renderer.ts
|
|
7178
7331
|
var DEFAULT_EDITOR_COLOR = "rgba(30, 40, 60, 0.45)";
|
|
7179
7332
|
var DEFAULT_PLAYER_COLOR = "#0b1020";
|
|
7180
7333
|
var FogRenderer = class {
|
|
7181
7334
|
tileCache = /* @__PURE__ */ new Map();
|
|
7335
|
+
patternCache = /* @__PURE__ */ new Map();
|
|
7182
7336
|
state = null;
|
|
7183
7337
|
viewMode = "off";
|
|
7184
7338
|
dirty = true;
|
|
7185
|
-
|
|
7186
|
-
|
|
7339
|
+
editorStyle;
|
|
7340
|
+
playerStyle;
|
|
7187
7341
|
constructor(options = {}) {
|
|
7188
|
-
this.
|
|
7189
|
-
|
|
7342
|
+
this.editorStyle = resolveFogStyle(
|
|
7343
|
+
options.editorStyle,
|
|
7344
|
+
options.editorColor,
|
|
7345
|
+
DEFAULT_EDITOR_COLOR
|
|
7346
|
+
);
|
|
7347
|
+
this.playerStyle = resolveFogStyle(
|
|
7348
|
+
options.playerStyle,
|
|
7349
|
+
options.playerColor,
|
|
7350
|
+
DEFAULT_PLAYER_COLOR
|
|
7351
|
+
);
|
|
7190
7352
|
}
|
|
7191
7353
|
setState(state) {
|
|
7192
7354
|
this.state = state;
|
|
@@ -7212,12 +7374,23 @@ var FogRenderer = class {
|
|
|
7212
7374
|
isVisible() {
|
|
7213
7375
|
return this.viewMode !== "off" && this.state !== null;
|
|
7214
7376
|
}
|
|
7377
|
+
getResolvedStyle(mode) {
|
|
7378
|
+
return mode === "editor" ? this.editorStyle : this.playerStyle;
|
|
7379
|
+
}
|
|
7215
7380
|
render(ctx, camera, viewportWidth, viewportHeight, _dpr) {
|
|
7216
7381
|
if (!this.state || this.viewMode === "off") return;
|
|
7217
7382
|
const def = this.state.definition;
|
|
7218
7383
|
const cellSize = def.cellSize;
|
|
7219
7384
|
const tileWorldSize = FOG_TILE_CELLS * cellSize;
|
|
7220
|
-
const
|
|
7385
|
+
const mode = this.viewMode === "editor" ? "editor" : "player";
|
|
7386
|
+
const style = this.getResolvedStyle(mode);
|
|
7387
|
+
const proceduralStyle = style.kind === "procedural" ? style : null;
|
|
7388
|
+
const color = style.kind === "procedural" ? normalizeCanvasColor(
|
|
7389
|
+
ctx,
|
|
7390
|
+
style.backdrop,
|
|
7391
|
+
mode === "player" ? DEFAULT_PLAYER_COLOR : DEFAULT_EDITOR_COLOR
|
|
7392
|
+
) : style.color;
|
|
7393
|
+
const safetyColor = proceduralStyle && mode === "player" ? DEFAULT_PLAYER_COLOR : null;
|
|
7221
7394
|
const worldBounds = getVisibleWorld(camera, viewportWidth, viewportHeight);
|
|
7222
7395
|
const minTX = Math.floor(Math.max(def.bounds.x, worldBounds.x) / tileWorldSize);
|
|
7223
7396
|
const minTY = Math.floor(Math.max(def.bounds.y, worldBounds.y) / tileWorldSize);
|
|
@@ -7248,7 +7421,22 @@ var FogRenderer = class {
|
|
|
7248
7421
|
const clipR = Math.min(tileWorldX + tileWorldSize, def.bounds.x + def.bounds.w);
|
|
7249
7422
|
const clipB = Math.min(tileWorldY + tileWorldSize, def.bounds.y + def.bounds.h);
|
|
7250
7423
|
if (clipR > clipX && clipB > clipY) {
|
|
7424
|
+
if (safetyColor) {
|
|
7425
|
+
ctx.fillStyle = safetyColor;
|
|
7426
|
+
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7427
|
+
}
|
|
7428
|
+
ctx.fillStyle = color;
|
|
7251
7429
|
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7430
|
+
if (proceduralStyle) {
|
|
7431
|
+
this.paintProceduralOverlay(
|
|
7432
|
+
ctx,
|
|
7433
|
+
proceduralStyle,
|
|
7434
|
+
clipX,
|
|
7435
|
+
clipY,
|
|
7436
|
+
clipR - clipX,
|
|
7437
|
+
clipB - clipY
|
|
7438
|
+
);
|
|
7439
|
+
}
|
|
7252
7440
|
}
|
|
7253
7441
|
continue;
|
|
7254
7442
|
}
|
|
@@ -7256,18 +7444,33 @@ var FogRenderer = class {
|
|
|
7256
7444
|
continue;
|
|
7257
7445
|
}
|
|
7258
7446
|
if (data) {
|
|
7447
|
+
if (safetyColor) this.renderTile(ctx, data, tx, ty, def, safetyColor);
|
|
7259
7448
|
this.renderTile(ctx, data, tx, ty, def, color);
|
|
7449
|
+
if (proceduralStyle) {
|
|
7450
|
+
this.renderTileProceduralOverlay(ctx, data, tx, ty, def, proceduralStyle);
|
|
7451
|
+
}
|
|
7260
7452
|
}
|
|
7261
7453
|
}
|
|
7262
7454
|
}
|
|
7263
7455
|
ctx.restore();
|
|
7264
7456
|
this.dirty = false;
|
|
7265
7457
|
}
|
|
7266
|
-
renderForExport(ctx, state, mode, color) {
|
|
7458
|
+
renderForExport(ctx, state, mode, color, style) {
|
|
7267
7459
|
const def = state.definition;
|
|
7268
7460
|
const cellSize = def.cellSize;
|
|
7269
7461
|
const tileWorldSize = FOG_TILE_CELLS * cellSize;
|
|
7270
|
-
const
|
|
7462
|
+
const resolved = style ? resolveFogStyle(
|
|
7463
|
+
style,
|
|
7464
|
+
void 0,
|
|
7465
|
+
mode === "editor" ? DEFAULT_EDITOR_COLOR : DEFAULT_PLAYER_COLOR
|
|
7466
|
+
) : this.getResolvedStyle(mode);
|
|
7467
|
+
const proceduralStyle = !color && resolved.kind === "procedural" ? resolved : null;
|
|
7468
|
+
const fogColor = color ?? (proceduralStyle ? normalizeCanvasColor(
|
|
7469
|
+
ctx,
|
|
7470
|
+
proceduralStyle.backdrop,
|
|
7471
|
+
mode === "player" ? DEFAULT_PLAYER_COLOR : DEFAULT_EDITOR_COLOR
|
|
7472
|
+
) : resolved.kind === "solid" ? resolved.color : resolved.backdrop);
|
|
7473
|
+
const safetyColor = proceduralStyle && mode === "player" ? DEFAULT_PLAYER_COLOR : null;
|
|
7271
7474
|
const baseCovered = def.base === "covered";
|
|
7272
7475
|
const tileMap = /* @__PURE__ */ new Map();
|
|
7273
7476
|
for (const tile of state.tiles) {
|
|
@@ -7290,20 +7493,129 @@ var FogRenderer = class {
|
|
|
7290
7493
|
const clipR = Math.min(tileWorldX + tileWorldSize, def.bounds.x + def.bounds.w);
|
|
7291
7494
|
const clipB = Math.min(tileWorldY + tileWorldSize, def.bounds.y + def.bounds.h);
|
|
7292
7495
|
if (clipR > clipX && clipB > clipY) {
|
|
7496
|
+
if (safetyColor) {
|
|
7497
|
+
ctx.fillStyle = safetyColor;
|
|
7498
|
+
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7499
|
+
}
|
|
7500
|
+
ctx.fillStyle = fogColor;
|
|
7293
7501
|
ctx.fillRect(clipX, clipY, clipR - clipX, clipB - clipY);
|
|
7502
|
+
if (proceduralStyle) {
|
|
7503
|
+
this.paintProceduralOverlay(
|
|
7504
|
+
ctx,
|
|
7505
|
+
proceduralStyle,
|
|
7506
|
+
clipX,
|
|
7507
|
+
clipY,
|
|
7508
|
+
clipR - clipX,
|
|
7509
|
+
clipB - clipY
|
|
7510
|
+
);
|
|
7511
|
+
}
|
|
7294
7512
|
}
|
|
7295
7513
|
continue;
|
|
7296
7514
|
}
|
|
7297
7515
|
if (data) {
|
|
7516
|
+
if (safetyColor) this.renderTileForExport(ctx, data, tx, ty, def, safetyColor);
|
|
7298
7517
|
this.renderTileForExport(ctx, data, tx, ty, def, fogColor);
|
|
7518
|
+
if (proceduralStyle) {
|
|
7519
|
+
this.renderTileProceduralOverlay(ctx, data, tx, ty, def, proceduralStyle);
|
|
7520
|
+
}
|
|
7299
7521
|
}
|
|
7300
7522
|
}
|
|
7301
7523
|
}
|
|
7302
7524
|
}
|
|
7303
7525
|
dispose() {
|
|
7304
7526
|
this.tileCache.clear();
|
|
7527
|
+
this.patternCache.clear();
|
|
7528
|
+
clearProceduralTileCache();
|
|
7305
7529
|
this.state = null;
|
|
7306
7530
|
}
|
|
7531
|
+
getOrCreatePattern(ctx, style, worldScale) {
|
|
7532
|
+
const key = `${style.backdrop}\0${style.tint}\0${style.opacity}\0${style.scale}\0${style.seed}\0${style.detail}\0${worldScale}`;
|
|
7533
|
+
const cached = this.patternCache.get(key);
|
|
7534
|
+
if (cached !== void 0) return cached;
|
|
7535
|
+
let pattern = null;
|
|
7536
|
+
try {
|
|
7537
|
+
const tileData = getCachedProceduralTile(style);
|
|
7538
|
+
pattern = this.createPatternFromTileData(ctx, tileData, style, worldScale);
|
|
7539
|
+
} catch {
|
|
7540
|
+
}
|
|
7541
|
+
if (this.patternCache.size >= 32) {
|
|
7542
|
+
const oldest = this.patternCache.keys().next().value;
|
|
7543
|
+
if (oldest !== void 0) this.patternCache.delete(oldest);
|
|
7544
|
+
}
|
|
7545
|
+
this.patternCache.set(key, pattern);
|
|
7546
|
+
return pattern;
|
|
7547
|
+
}
|
|
7548
|
+
createPatternFromTileData(ctx, tileData, style, worldScale) {
|
|
7549
|
+
if (typeof document === "undefined") return null;
|
|
7550
|
+
const sourceCanvas = document.createElement("canvas");
|
|
7551
|
+
sourceCanvas.width = tileData.width;
|
|
7552
|
+
sourceCanvas.height = tileData.height;
|
|
7553
|
+
const sourceCtx = sourceCanvas.getContext("2d");
|
|
7554
|
+
if (!sourceCtx) return null;
|
|
7555
|
+
const imageData = new ImageData(
|
|
7556
|
+
new Uint8ClampedArray(tileData.data),
|
|
7557
|
+
tileData.width,
|
|
7558
|
+
tileData.height
|
|
7559
|
+
);
|
|
7560
|
+
sourceCtx.putImageData(imageData, 0, 0);
|
|
7561
|
+
sourceCtx.globalCompositeOperation = "source-in";
|
|
7562
|
+
sourceCtx.fillStyle = normalizeCanvasColor(sourceCtx, style.tint, "#ffffff");
|
|
7563
|
+
sourceCtx.fillRect(0, 0, tileData.width, tileData.height);
|
|
7564
|
+
sourceCtx.globalCompositeOperation = "source-over";
|
|
7565
|
+
const patternScale = style.scale * worldScale / tileData.width;
|
|
7566
|
+
const pattern = ctx.createPattern(sourceCanvas, "repeat");
|
|
7567
|
+
if (pattern && typeof pattern.setTransform === "function" && typeof DOMMatrix !== "undefined") {
|
|
7568
|
+
try {
|
|
7569
|
+
pattern.setTransform(new DOMMatrix([patternScale, 0, 0, patternScale, 0, 0]));
|
|
7570
|
+
return pattern;
|
|
7571
|
+
} catch {
|
|
7572
|
+
}
|
|
7573
|
+
}
|
|
7574
|
+
const patternPx = Math.round(style.scale * worldScale);
|
|
7575
|
+
if (patternPx < 1) return null;
|
|
7576
|
+
const patternCanvas = document.createElement("canvas");
|
|
7577
|
+
patternCanvas.width = patternPx;
|
|
7578
|
+
patternCanvas.height = patternPx;
|
|
7579
|
+
const patternCtx = patternCanvas.getContext("2d");
|
|
7580
|
+
if (!patternCtx) return null;
|
|
7581
|
+
patternCtx.drawImage(sourceCanvas, 0, 0, patternPx, patternPx);
|
|
7582
|
+
return ctx.createPattern(patternCanvas, "repeat");
|
|
7583
|
+
}
|
|
7584
|
+
paintProceduralOverlay(ctx, style, x, y, w, h) {
|
|
7585
|
+
const pattern = this.getOrCreatePattern(ctx, style, 1);
|
|
7586
|
+
if (!pattern) return;
|
|
7587
|
+
ctx.save();
|
|
7588
|
+
ctx.fillStyle = pattern;
|
|
7589
|
+
ctx.fillRect(x, y, w, h);
|
|
7590
|
+
ctx.restore();
|
|
7591
|
+
}
|
|
7592
|
+
renderTileProceduralOverlay(ctx, data, tx, ty, def, style) {
|
|
7593
|
+
const cellSize = def.cellSize;
|
|
7594
|
+
const tileWorldX = tx * FOG_TILE_CELLS * cellSize;
|
|
7595
|
+
const tileWorldY = ty * FOG_TILE_CELLS * cellSize;
|
|
7596
|
+
const pattern = this.getOrCreatePattern(ctx, style, 1);
|
|
7597
|
+
if (!pattern) return;
|
|
7598
|
+
const bytes = decodeBase64(data);
|
|
7599
|
+
ctx.save();
|
|
7600
|
+
ctx.fillStyle = pattern;
|
|
7601
|
+
for (let row = 0; row < FOG_TILE_CELLS; row++) {
|
|
7602
|
+
for (let col = 0; col < FOG_TILE_CELLS; col++) {
|
|
7603
|
+
const cellWorldX = tileWorldX + col * cellSize;
|
|
7604
|
+
const cellWorldY = tileWorldY + row * cellSize;
|
|
7605
|
+
if (cellWorldX < def.bounds.x || cellWorldY < def.bounds.y || cellWorldX >= def.bounds.x + def.bounds.w || cellWorldY >= def.bounds.y + def.bounds.h) {
|
|
7606
|
+
continue;
|
|
7607
|
+
}
|
|
7608
|
+
const index = row * FOG_TILE_CELLS + col;
|
|
7609
|
+
const byteIndex = index >> 3;
|
|
7610
|
+
const bitIndex = 7 - (index & 7);
|
|
7611
|
+
const revealed = (bytes[byteIndex] >> bitIndex & 1) === 1;
|
|
7612
|
+
if (!revealed) {
|
|
7613
|
+
ctx.fillRect(cellWorldX, cellWorldY, cellSize, cellSize);
|
|
7614
|
+
}
|
|
7615
|
+
}
|
|
7616
|
+
}
|
|
7617
|
+
ctx.restore();
|
|
7618
|
+
}
|
|
7307
7619
|
tileRaster(data, color) {
|
|
7308
7620
|
const key = `${color}\0${data}`;
|
|
7309
7621
|
const cached = this.tileCache.get(key);
|
|
@@ -7387,6 +7699,22 @@ function getVisibleWorld(camera, viewportWidth, viewportHeight) {
|
|
|
7387
7699
|
h: bottomRight.y - topLeft.y
|
|
7388
7700
|
};
|
|
7389
7701
|
}
|
|
7702
|
+
function normalizeCanvasColor(ctx, value, fallback) {
|
|
7703
|
+
const previous = ctx.fillStyle;
|
|
7704
|
+
try {
|
|
7705
|
+
ctx.fillStyle = "#010203";
|
|
7706
|
+
ctx.fillStyle = value;
|
|
7707
|
+
const first = ctx.fillStyle;
|
|
7708
|
+
ctx.fillStyle = "#040506";
|
|
7709
|
+
ctx.fillStyle = value;
|
|
7710
|
+
const second = ctx.fillStyle;
|
|
7711
|
+
return typeof first === "string" && first === second ? first : fallback;
|
|
7712
|
+
} catch {
|
|
7713
|
+
return fallback;
|
|
7714
|
+
} finally {
|
|
7715
|
+
ctx.fillStyle = previous;
|
|
7716
|
+
}
|
|
7717
|
+
}
|
|
7390
7718
|
|
|
7391
7719
|
// src/canvas/export-image.ts
|
|
7392
7720
|
var DEFAULT_IMAGE_TIMEOUT_MS = 1e4;
|
|
@@ -7802,7 +8130,13 @@ async function exportImage(store, options = {}, layerManager) {
|
|
|
7802
8130
|
}
|
|
7803
8131
|
if (options.fog) {
|
|
7804
8132
|
const fogRenderer = new FogRenderer();
|
|
7805
|
-
fogRenderer.renderForExport(
|
|
8133
|
+
fogRenderer.renderForExport(
|
|
8134
|
+
ctx,
|
|
8135
|
+
options.fog.state,
|
|
8136
|
+
options.fog.mode,
|
|
8137
|
+
options.fog.color,
|
|
8138
|
+
options.fog.style
|
|
8139
|
+
);
|
|
7806
8140
|
}
|
|
7807
8141
|
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
7808
8142
|
return new Promise((resolve) => {
|
|
@@ -8196,7 +8530,13 @@ async function exportSvg(store, options = {}, layerManager) {
|
|
|
8196
8530
|
if (fogCtx) {
|
|
8197
8531
|
fogCtx.translate(-bounds.x, -bounds.y);
|
|
8198
8532
|
const fogRenderer = new FogRenderer();
|
|
8199
|
-
fogRenderer.renderForExport(
|
|
8533
|
+
fogRenderer.renderForExport(
|
|
8534
|
+
fogCtx,
|
|
8535
|
+
fogState,
|
|
8536
|
+
options.fog.mode,
|
|
8537
|
+
options.fog.color,
|
|
8538
|
+
options.fog.style
|
|
8539
|
+
);
|
|
8200
8540
|
try {
|
|
8201
8541
|
const fogDataUri = fogCanvas.toDataURL("image/png");
|
|
8202
8542
|
if (fogDataUri.startsWith("data:")) {
|
|
@@ -11191,26 +11531,35 @@ var Viewport = class _Viewport {
|
|
|
11191
11531
|
const expected = base.expectedCanvasTypes ? /* @__PURE__ */ new Set([...declared, ...base.expectedCanvasTypes]) : declared;
|
|
11192
11532
|
return { ...base, htmlPainters: registry, expectedCanvasTypes: expected };
|
|
11193
11533
|
}
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11534
|
+
/**
|
|
11535
|
+
* Carry constructor-configured fog presentation into both implicit exports and
|
|
11536
|
+
* explicit state/mode exports. Explicit style and legacy color overrides win.
|
|
11537
|
+
*/
|
|
11538
|
+
withFogDefaults(options) {
|
|
11539
|
+
const fog = options.fog;
|
|
11540
|
+
if (fog === false) return options;
|
|
11541
|
+
if (fog !== void 0) {
|
|
11542
|
+
if (fog.style !== void 0 || fog.color !== void 0) return options;
|
|
11543
|
+
return {
|
|
11544
|
+
...options,
|
|
11545
|
+
fog: { ...fog, style: this.fogRenderer.getResolvedStyle(fog.mode) }
|
|
11546
|
+
};
|
|
11202
11547
|
}
|
|
11548
|
+
if (!this.fogRenderer.isVisible()) return options;
|
|
11549
|
+
const state = this.fogManager.getState();
|
|
11550
|
+
if (!state) return options;
|
|
11551
|
+
const mode = this.fogRenderer.getViewMode();
|
|
11552
|
+
return {
|
|
11553
|
+
...options,
|
|
11554
|
+
fog: { state, mode, style: this.fogRenderer.getResolvedStyle(mode) }
|
|
11555
|
+
};
|
|
11556
|
+
}
|
|
11557
|
+
async exportImage(options) {
|
|
11558
|
+
const opts = this.withFogDefaults(this.withHtmlDefaults(options));
|
|
11203
11559
|
return exportImage(this.store, opts, this.layerManager);
|
|
11204
11560
|
}
|
|
11205
11561
|
async exportSVG(options) {
|
|
11206
|
-
const opts = this.withHtmlDefaults(options);
|
|
11207
|
-
if (opts.fog === void 0 && this.fogRenderer.isVisible()) {
|
|
11208
|
-
const state = this.fogManager.getState();
|
|
11209
|
-
if (state) {
|
|
11210
|
-
const mode = this.fogRenderer.getViewMode();
|
|
11211
|
-
opts.fog = { state, mode };
|
|
11212
|
-
}
|
|
11213
|
-
}
|
|
11562
|
+
const opts = this.withFogDefaults(this.withHtmlDefaults(options));
|
|
11214
11563
|
return exportSvg(this.store, opts, this.layerManager);
|
|
11215
11564
|
}
|
|
11216
11565
|
loadState(state) {
|
|
@@ -12844,15 +13193,15 @@ function applyCameraView(camera, view, canvasW, canvasH) {
|
|
|
12844
13193
|
var DEFAULT_DURATION_MS3 = 400;
|
|
12845
13194
|
var FRAMED_EPSILON = 1e-6;
|
|
12846
13195
|
var easeOutCubic2 = (t) => 1 - Math.pow(1 - t, 3);
|
|
12847
|
-
function
|
|
13196
|
+
function lerp2(a, b, k) {
|
|
12848
13197
|
return a + (b - a) * k;
|
|
12849
13198
|
}
|
|
12850
13199
|
function lerpView(from, to, k) {
|
|
12851
13200
|
return {
|
|
12852
|
-
x:
|
|
12853
|
-
y:
|
|
12854
|
-
w:
|
|
12855
|
-
h:
|
|
13201
|
+
x: lerp2(from.x, to.x, k),
|
|
13202
|
+
y: lerp2(from.y, to.y, k),
|
|
13203
|
+
w: lerp2(from.w, to.w, k),
|
|
13204
|
+
h: lerp2(from.h, to.h, k)
|
|
12856
13205
|
};
|
|
12857
13206
|
}
|
|
12858
13207
|
function viewsClose(a, b) {
|
|
@@ -14106,7 +14455,7 @@ var PencilTool = class {
|
|
|
14106
14455
|
};
|
|
14107
14456
|
|
|
14108
14457
|
// src/elements/stroke-erase.ts
|
|
14109
|
-
function
|
|
14458
|
+
function lerp3(a, b, t) {
|
|
14110
14459
|
return {
|
|
14111
14460
|
x: a.x + (b.x - a.x) * t,
|
|
14112
14461
|
y: a.y + (b.y - a.y) * t,
|
|
@@ -14165,13 +14514,13 @@ function erasePoints(points, eraser, radius) {
|
|
|
14165
14514
|
erased = true;
|
|
14166
14515
|
if (tLo > 0) {
|
|
14167
14516
|
if (current.length === 0) current.push(a);
|
|
14168
|
-
current.push(
|
|
14517
|
+
current.push(lerp3(a, b, tLo));
|
|
14169
14518
|
flush();
|
|
14170
14519
|
} else {
|
|
14171
14520
|
flush();
|
|
14172
14521
|
}
|
|
14173
14522
|
if (tHi < 1) {
|
|
14174
|
-
current = [
|
|
14523
|
+
current = [lerp3(a, b, tHi), b];
|
|
14175
14524
|
}
|
|
14176
14525
|
}
|
|
14177
14526
|
flush();
|
|
@@ -16687,7 +17036,7 @@ var FogTool = class {
|
|
|
16687
17036
|
};
|
|
16688
17037
|
|
|
16689
17038
|
// src/index.ts
|
|
16690
|
-
var VERSION = "0.
|
|
17039
|
+
var VERSION = "0.67.0";
|
|
16691
17040
|
export {
|
|
16692
17041
|
AWARENESS_MAX_SELECTION,
|
|
16693
17042
|
AWARENESS_PRESENCE_KIND,
|
|
@@ -16795,6 +17144,7 @@ export {
|
|
|
16795
17144
|
isPingPresence,
|
|
16796
17145
|
pathDistanceCells,
|
|
16797
17146
|
recommendedFogCellSize,
|
|
17147
|
+
resolveFogStyle,
|
|
16798
17148
|
resolveHtmlRouting,
|
|
16799
17149
|
setFontSize,
|
|
16800
17150
|
smartSnap,
|