quake2ts 0.0.596 → 0.0.598

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.
@@ -8,7 +8,7 @@ import { ConfigStringEntry, Cvar, Camera } from '@quake2ts/engine';
8
8
  export { ConfigStringEntry, Cvar } from '@quake2ts/engine';
9
9
  import { GameStateSnapshot, Entity, ScriptHookRegistry, SpawnContext, EntitySystem, SpawnRegistry, MonsterMove, DamageMod, PlayerInventory, BaseItem, WeaponId, WeaponItem, HealthItem, ArmorItem, AmmoItemId, PowerupItem, GameExports } from '@quake2ts/game';
10
10
  import { NetworkTransport, Server, ServerStatic, Client, ClientState, ClientFrame } from '@quake2ts/server';
11
- import { ImageData } from '@napi-rs/canvas';
11
+ import { ImageData, Canvas } from '@napi-rs/canvas';
12
12
  import { vec3 } from 'gl-matrix';
13
13
 
14
14
  interface BinaryWriterMock {
@@ -1270,12 +1270,25 @@ interface VisualDiff {
1270
1270
  diffImage?: Buffer;
1271
1271
  }
1272
1272
  /**
1273
- * Captures a screenshot of the game.
1273
+ * Captures a screenshot of the game using Playwright.
1274
+ * @param page Playwright Page object
1275
+ * @param name Output filename (without extension)
1274
1276
  */
1275
1277
  declare function captureGameScreenshot(page: any, name: string): Promise<Buffer>;
1278
+ /**
1279
+ * Saves a canvas to a PNG file.
1280
+ * Compatible with both JSDOM/HTMLCanvasElement and @napi-rs/canvas.
1281
+ */
1282
+ declare function takeScreenshot(canvas: Canvas | HTMLCanvasElement, filepath: string): Promise<void>;
1283
+ /**
1284
+ * Compares a canvas state against a baseline image file.
1285
+ * Returns true if they match (within optional threshold logic, currently strict pixel match).
1286
+ * If baseline does not exist, it saves the current state as baseline and returns true.
1287
+ */
1288
+ declare function compareScreenshot(canvas: Canvas | HTMLCanvasElement, baselinePath: string): Promise<boolean>;
1276
1289
  /**
1277
1290
  * Compares two screenshots (Buffers).
1278
- * Uses a pixel comparison library if available, or simple buffer check.
1291
+ * Uses simple buffer check. Kept for backward compatibility or direct buffer comparison.
1279
1292
  */
1280
1293
  declare function compareScreenshots(baseline: Buffer, current: Buffer, threshold?: number): VisualDiff;
1281
1294
  interface VisualScenario {
@@ -1287,4 +1300,4 @@ interface VisualScenario {
1287
1300
  */
1288
1301
  declare function createVisualTestScenario(sceneName: string): VisualScenario;
1289
1302
 
1290
- export { type AudioEvent, type BandwidthScenario, type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, type CameraInput, type Connection, type ConsistencyReport, type ControlledTimer, type DeltaSnapshot, type DrawCall, type GameState, type GameStateCapture, type Handshake, HandshakeStage, InputInjector, type KeyModifiers, type MasterServer, type Message, type MessageReaderMock, type MessageWriterMock, type MockAI, type MockCollisionEntityIndex, type MockDamageInfo, type MockEngine, type MockGame, type MockMonsterAI, MockNetworkTransport, MockPointerLock, type MockRAF, type MockRConClient, type MockRenderingContext, type MockServer, type MockServerConsole, type MockServerContext, MockTransport, type MockUDPSocket, MockWebGL2RenderingContext, type MultiplayerScenario, type NetworkAddress, type NetworkCondition, type NetworkSimulator, type NodeSetupOptions, type PacketMock, type PlaywrightOptions, type PlaywrightTestClient, type RateLimiter, type RecordedPacket, type RefDef, type ServerInfo, type ServerListFilter, type Snapshot, type StorageScenario, type SurfaceMock, type TestContext, type TraceMock, type Transform, type UserInfo, type ViewScenario, type ViewState, type VisualDiff, type VisualScenario, captureAudioEvents, captureCanvasDrawCalls, captureGameScreenshot, captureGameState, compareScreenshots, createBandwidthTestScenario, createBinaryStreamMock, createBinaryWriterMock, createBounds, createCombatTestContext, createConfigStringArrayMock, createConfigStringMock, createControlledTimer, createCustomNetworkCondition, createCvarMock, createDeltaSnapshot, createEntity, createEntityFactory, createEntityStateFactory, createGameStateSnapshotFactory, createInputInjector, createItemEntityFactory, createMessageReaderMock, createMessageWriterMock, createMockAI, createMockAmmoItem, createMockArmorItem, createMockCamera, createMockCanvas, createMockCanvasContext2D, createMockCollisionEntityIndex, createMockConnection, createMockDamageInfo, createMockEngine, createMockGPUAdapter, createMockGPUCanvasContext, createMockGPUDevice, createMockGame, createMockGameExports, createMockGameState, createMockHandshake, createMockHealthItem, createMockImage, createMockImageData, createMockIndexedDB, createMockInventory, createMockItem, createMockKeyboardEvent, createMockLocalStorage, createMockMasterServer, createMockMonsterAI, createMockMonsterMove, createMockMouseEvent, createMockNetDriver, createMockNetworkAddress, createMockPerformance, createMockPointerLock, createMockPowerupItem, createMockRAF, createMockRConClient, createMockRateLimiter, createMockRefDef, createMockRenderingContext, createMockServer, createMockServerClient, createMockServerConsole, createMockServerInfo, createMockServerState, createMockServerStatic, createMockSessionStorage, createMockTransport, createMockUDPSocket, createMockUserInfo, createMockViewState, createMockWeapon, createMockWeaponItem, createMockWebGL2Context, createMockWheelEvent, createMonsterEntityFactory, createMultiplayerTestScenario, createNetChanMock, createPacketMock, createPhysicsTestContext, createPlayerEntityFactory, createPlayerStateFactory, createPlaywrightTestClient, createProjectileEntityFactory, createServerSnapshot, createSpawnTestContext, createStorageTestScenario, createSurfaceMock, createTestContext, createTraceMock, createTransform, createTriggerEntityFactory, createVector3, createViewTestScenario, createVisualTestScenario, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, measureSnapshotSize, mockMonsterAttacks, randomVector3, serializeUserInfo, setupBrowserEnvironment, setupMockAudioContext, setupNodeEnvironment, setupWebGPUMocks, simulateBandwidthLimit, simulateCameraMovement, simulateFrames, simulateHandshake, simulateNetworkCondition, simulatePlayerInput, simulatePlayerJoin, simulatePlayerLeave, simulateServerCommand, simulateServerRegistration, simulateServerTick, simulateSnapshotDelivery, teardownBrowserEnvironment, teardownMockAudioContext, teardownNodeEnvironment, throttleBandwidth, verifySnapshotConsistency, waitForGameReady };
1303
+ export { type AudioEvent, type BandwidthScenario, type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, type CameraInput, type Connection, type ConsistencyReport, type ControlledTimer, type DeltaSnapshot, type DrawCall, type GameState, type GameStateCapture, type Handshake, HandshakeStage, InputInjector, type KeyModifiers, type MasterServer, type Message, type MessageReaderMock, type MessageWriterMock, type MockAI, type MockCollisionEntityIndex, type MockDamageInfo, type MockEngine, type MockGame, type MockMonsterAI, MockNetworkTransport, MockPointerLock, type MockRAF, type MockRConClient, type MockRenderingContext, type MockServer, type MockServerConsole, type MockServerContext, MockTransport, type MockUDPSocket, MockWebGL2RenderingContext, type MultiplayerScenario, type NetworkAddress, type NetworkCondition, type NetworkSimulator, type NodeSetupOptions, type PacketMock, type PlaywrightOptions, type PlaywrightTestClient, type RateLimiter, type RecordedPacket, type RefDef, type ServerInfo, type ServerListFilter, type Snapshot, type StorageScenario, type SurfaceMock, type TestContext, type TraceMock, type Transform, type UserInfo, type ViewScenario, type ViewState, type VisualDiff, type VisualScenario, captureAudioEvents, captureCanvasDrawCalls, captureGameScreenshot, captureGameState, compareScreenshot, compareScreenshots, createBandwidthTestScenario, createBinaryStreamMock, createBinaryWriterMock, createBounds, createCombatTestContext, createConfigStringArrayMock, createConfigStringMock, createControlledTimer, createCustomNetworkCondition, createCvarMock, createDeltaSnapshot, createEntity, createEntityFactory, createEntityStateFactory, createGameStateSnapshotFactory, createInputInjector, createItemEntityFactory, createMessageReaderMock, createMessageWriterMock, createMockAI, createMockAmmoItem, createMockArmorItem, createMockCamera, createMockCanvas, createMockCanvasContext2D, createMockCollisionEntityIndex, createMockConnection, createMockDamageInfo, createMockEngine, createMockGPUAdapter, createMockGPUCanvasContext, createMockGPUDevice, createMockGame, createMockGameExports, createMockGameState, createMockHandshake, createMockHealthItem, createMockImage, createMockImageData, createMockIndexedDB, createMockInventory, createMockItem, createMockKeyboardEvent, createMockLocalStorage, createMockMasterServer, createMockMonsterAI, createMockMonsterMove, createMockMouseEvent, createMockNetDriver, createMockNetworkAddress, createMockPerformance, createMockPointerLock, createMockPowerupItem, createMockRAF, createMockRConClient, createMockRateLimiter, createMockRefDef, createMockRenderingContext, createMockServer, createMockServerClient, createMockServerConsole, createMockServerInfo, createMockServerState, createMockServerStatic, createMockSessionStorage, createMockTransport, createMockUDPSocket, createMockUserInfo, createMockViewState, createMockWeapon, createMockWeaponItem, createMockWebGL2Context, createMockWheelEvent, createMonsterEntityFactory, createMultiplayerTestScenario, createNetChanMock, createPacketMock, createPhysicsTestContext, createPlayerEntityFactory, createPlayerStateFactory, createPlaywrightTestClient, createProjectileEntityFactory, createServerSnapshot, createSpawnTestContext, createStorageTestScenario, createSurfaceMock, createTestContext, createTraceMock, createTransform, createTriggerEntityFactory, createVector3, createViewTestScenario, createVisualTestScenario, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, measureSnapshotSize, mockMonsterAttacks, randomVector3, serializeUserInfo, setupBrowserEnvironment, setupMockAudioContext, setupNodeEnvironment, setupWebGPUMocks, simulateBandwidthLimit, simulateCameraMovement, simulateFrames, simulateHandshake, simulateNetworkCondition, simulatePlayerInput, simulatePlayerJoin, simulatePlayerLeave, simulateServerCommand, simulateServerRegistration, simulateServerTick, simulateSnapshotDelivery, takeScreenshot, teardownBrowserEnvironment, teardownMockAudioContext, teardownNodeEnvironment, throttleBandwidth, verifySnapshotConsistency, waitForGameReady };
@@ -8,7 +8,7 @@ import { ConfigStringEntry, Cvar, Camera } from '@quake2ts/engine';
8
8
  export { ConfigStringEntry, Cvar } from '@quake2ts/engine';
9
9
  import { GameStateSnapshot, Entity, ScriptHookRegistry, SpawnContext, EntitySystem, SpawnRegistry, MonsterMove, DamageMod, PlayerInventory, BaseItem, WeaponId, WeaponItem, HealthItem, ArmorItem, AmmoItemId, PowerupItem, GameExports } from '@quake2ts/game';
10
10
  import { NetworkTransport, Server, ServerStatic, Client, ClientState, ClientFrame } from '@quake2ts/server';
11
- import { ImageData } from '@napi-rs/canvas';
11
+ import { ImageData, Canvas } from '@napi-rs/canvas';
12
12
  import { vec3 } from 'gl-matrix';
13
13
 
14
14
  interface BinaryWriterMock {
@@ -1270,12 +1270,25 @@ interface VisualDiff {
1270
1270
  diffImage?: Buffer;
1271
1271
  }
1272
1272
  /**
1273
- * Captures a screenshot of the game.
1273
+ * Captures a screenshot of the game using Playwright.
1274
+ * @param page Playwright Page object
1275
+ * @param name Output filename (without extension)
1274
1276
  */
1275
1277
  declare function captureGameScreenshot(page: any, name: string): Promise<Buffer>;
1278
+ /**
1279
+ * Saves a canvas to a PNG file.
1280
+ * Compatible with both JSDOM/HTMLCanvasElement and @napi-rs/canvas.
1281
+ */
1282
+ declare function takeScreenshot(canvas: Canvas | HTMLCanvasElement, filepath: string): Promise<void>;
1283
+ /**
1284
+ * Compares a canvas state against a baseline image file.
1285
+ * Returns true if they match (within optional threshold logic, currently strict pixel match).
1286
+ * If baseline does not exist, it saves the current state as baseline and returns true.
1287
+ */
1288
+ declare function compareScreenshot(canvas: Canvas | HTMLCanvasElement, baselinePath: string): Promise<boolean>;
1276
1289
  /**
1277
1290
  * Compares two screenshots (Buffers).
1278
- * Uses a pixel comparison library if available, or simple buffer check.
1291
+ * Uses simple buffer check. Kept for backward compatibility or direct buffer comparison.
1279
1292
  */
1280
1293
  declare function compareScreenshots(baseline: Buffer, current: Buffer, threshold?: number): VisualDiff;
1281
1294
  interface VisualScenario {
@@ -1287,4 +1300,4 @@ interface VisualScenario {
1287
1300
  */
1288
1301
  declare function createVisualTestScenario(sceneName: string): VisualScenario;
1289
1302
 
1290
- export { type AudioEvent, type BandwidthScenario, type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, type CameraInput, type Connection, type ConsistencyReport, type ControlledTimer, type DeltaSnapshot, type DrawCall, type GameState, type GameStateCapture, type Handshake, HandshakeStage, InputInjector, type KeyModifiers, type MasterServer, type Message, type MessageReaderMock, type MessageWriterMock, type MockAI, type MockCollisionEntityIndex, type MockDamageInfo, type MockEngine, type MockGame, type MockMonsterAI, MockNetworkTransport, MockPointerLock, type MockRAF, type MockRConClient, type MockRenderingContext, type MockServer, type MockServerConsole, type MockServerContext, MockTransport, type MockUDPSocket, MockWebGL2RenderingContext, type MultiplayerScenario, type NetworkAddress, type NetworkCondition, type NetworkSimulator, type NodeSetupOptions, type PacketMock, type PlaywrightOptions, type PlaywrightTestClient, type RateLimiter, type RecordedPacket, type RefDef, type ServerInfo, type ServerListFilter, type Snapshot, type StorageScenario, type SurfaceMock, type TestContext, type TraceMock, type Transform, type UserInfo, type ViewScenario, type ViewState, type VisualDiff, type VisualScenario, captureAudioEvents, captureCanvasDrawCalls, captureGameScreenshot, captureGameState, compareScreenshots, createBandwidthTestScenario, createBinaryStreamMock, createBinaryWriterMock, createBounds, createCombatTestContext, createConfigStringArrayMock, createConfigStringMock, createControlledTimer, createCustomNetworkCondition, createCvarMock, createDeltaSnapshot, createEntity, createEntityFactory, createEntityStateFactory, createGameStateSnapshotFactory, createInputInjector, createItemEntityFactory, createMessageReaderMock, createMessageWriterMock, createMockAI, createMockAmmoItem, createMockArmorItem, createMockCamera, createMockCanvas, createMockCanvasContext2D, createMockCollisionEntityIndex, createMockConnection, createMockDamageInfo, createMockEngine, createMockGPUAdapter, createMockGPUCanvasContext, createMockGPUDevice, createMockGame, createMockGameExports, createMockGameState, createMockHandshake, createMockHealthItem, createMockImage, createMockImageData, createMockIndexedDB, createMockInventory, createMockItem, createMockKeyboardEvent, createMockLocalStorage, createMockMasterServer, createMockMonsterAI, createMockMonsterMove, createMockMouseEvent, createMockNetDriver, createMockNetworkAddress, createMockPerformance, createMockPointerLock, createMockPowerupItem, createMockRAF, createMockRConClient, createMockRateLimiter, createMockRefDef, createMockRenderingContext, createMockServer, createMockServerClient, createMockServerConsole, createMockServerInfo, createMockServerState, createMockServerStatic, createMockSessionStorage, createMockTransport, createMockUDPSocket, createMockUserInfo, createMockViewState, createMockWeapon, createMockWeaponItem, createMockWebGL2Context, createMockWheelEvent, createMonsterEntityFactory, createMultiplayerTestScenario, createNetChanMock, createPacketMock, createPhysicsTestContext, createPlayerEntityFactory, createPlayerStateFactory, createPlaywrightTestClient, createProjectileEntityFactory, createServerSnapshot, createSpawnTestContext, createStorageTestScenario, createSurfaceMock, createTestContext, createTraceMock, createTransform, createTriggerEntityFactory, createVector3, createViewTestScenario, createVisualTestScenario, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, measureSnapshotSize, mockMonsterAttacks, randomVector3, serializeUserInfo, setupBrowserEnvironment, setupMockAudioContext, setupNodeEnvironment, setupWebGPUMocks, simulateBandwidthLimit, simulateCameraMovement, simulateFrames, simulateHandshake, simulateNetworkCondition, simulatePlayerInput, simulatePlayerJoin, simulatePlayerLeave, simulateServerCommand, simulateServerRegistration, simulateServerTick, simulateSnapshotDelivery, teardownBrowserEnvironment, teardownMockAudioContext, teardownNodeEnvironment, throttleBandwidth, verifySnapshotConsistency, waitForGameReady };
1303
+ export { type AudioEvent, type BandwidthScenario, type BinaryStreamMock, type BinaryWriterMock, type BrowserSetupOptions, type CameraInput, type Connection, type ConsistencyReport, type ControlledTimer, type DeltaSnapshot, type DrawCall, type GameState, type GameStateCapture, type Handshake, HandshakeStage, InputInjector, type KeyModifiers, type MasterServer, type Message, type MessageReaderMock, type MessageWriterMock, type MockAI, type MockCollisionEntityIndex, type MockDamageInfo, type MockEngine, type MockGame, type MockMonsterAI, MockNetworkTransport, MockPointerLock, type MockRAF, type MockRConClient, type MockRenderingContext, type MockServer, type MockServerConsole, type MockServerContext, MockTransport, type MockUDPSocket, MockWebGL2RenderingContext, type MultiplayerScenario, type NetworkAddress, type NetworkCondition, type NetworkSimulator, type NodeSetupOptions, type PacketMock, type PlaywrightOptions, type PlaywrightTestClient, type RateLimiter, type RecordedPacket, type RefDef, type ServerInfo, type ServerListFilter, type Snapshot, type StorageScenario, type SurfaceMock, type TestContext, type TraceMock, type Transform, type UserInfo, type ViewScenario, type ViewState, type VisualDiff, type VisualScenario, captureAudioEvents, captureCanvasDrawCalls, captureGameScreenshot, captureGameState, compareScreenshot, compareScreenshots, createBandwidthTestScenario, createBinaryStreamMock, createBinaryWriterMock, createBounds, createCombatTestContext, createConfigStringArrayMock, createConfigStringMock, createControlledTimer, createCustomNetworkCondition, createCvarMock, createDeltaSnapshot, createEntity, createEntityFactory, createEntityStateFactory, createGameStateSnapshotFactory, createInputInjector, createItemEntityFactory, createMessageReaderMock, createMessageWriterMock, createMockAI, createMockAmmoItem, createMockArmorItem, createMockCamera, createMockCanvas, createMockCanvasContext2D, createMockCollisionEntityIndex, createMockConnection, createMockDamageInfo, createMockEngine, createMockGPUAdapter, createMockGPUCanvasContext, createMockGPUDevice, createMockGame, createMockGameExports, createMockGameState, createMockHandshake, createMockHealthItem, createMockImage, createMockImageData, createMockIndexedDB, createMockInventory, createMockItem, createMockKeyboardEvent, createMockLocalStorage, createMockMasterServer, createMockMonsterAI, createMockMonsterMove, createMockMouseEvent, createMockNetDriver, createMockNetworkAddress, createMockPerformance, createMockPointerLock, createMockPowerupItem, createMockRAF, createMockRConClient, createMockRateLimiter, createMockRefDef, createMockRenderingContext, createMockServer, createMockServerClient, createMockServerConsole, createMockServerInfo, createMockServerState, createMockServerStatic, createMockSessionStorage, createMockTransport, createMockUDPSocket, createMockUserInfo, createMockViewState, createMockWeapon, createMockWeaponItem, createMockWebGL2Context, createMockWheelEvent, createMonsterEntityFactory, createMultiplayerTestScenario, createNetChanMock, createPacketMock, createPhysicsTestContext, createPlayerEntityFactory, createPlayerStateFactory, createPlaywrightTestClient, createProjectileEntityFactory, createServerSnapshot, createSpawnTestContext, createStorageTestScenario, createSurfaceMock, createTestContext, createTraceMock, createTransform, createTriggerEntityFactory, createVector3, createViewTestScenario, createVisualTestScenario, makeAxisBrush, makeBrushFromMinsMaxs, makeBspModel, makeLeaf, makeLeafModel, makeNode, makePlane, measureSnapshotSize, mockMonsterAttacks, randomVector3, serializeUserInfo, setupBrowserEnvironment, setupMockAudioContext, setupNodeEnvironment, setupWebGPUMocks, simulateBandwidthLimit, simulateCameraMovement, simulateFrames, simulateHandshake, simulateNetworkCondition, simulatePlayerInput, simulatePlayerJoin, simulatePlayerLeave, simulateServerCommand, simulateServerRegistration, simulateServerTick, simulateSnapshotDelivery, takeScreenshot, teardownBrowserEnvironment, teardownMockAudioContext, teardownNodeEnvironment, throttleBandwidth, verifySnapshotConsistency, waitForGameReady };
@@ -3086,9 +3086,81 @@ function throttleBandwidth(bytesPerSecond) {
3086
3086
  }
3087
3087
 
3088
3088
  // src/e2e/visual.ts
3089
+ import { Canvas as Canvas3, Image as Image2 } from "@napi-rs/canvas";
3090
+ import fs from "fs/promises";
3091
+ import path from "path";
3089
3092
  async function captureGameScreenshot(page, name) {
3090
3093
  return await page.screenshot({ path: `${name}.png` });
3091
3094
  }
3095
+ async function takeScreenshot(canvas, filepath) {
3096
+ let buffer;
3097
+ if ("toBuffer" in canvas && typeof canvas.toBuffer === "function") {
3098
+ buffer = canvas.toBuffer("image/png");
3099
+ } else if ("toDataURL" in canvas) {
3100
+ const dataUrl = canvas.toDataURL("image/png");
3101
+ const base64 = dataUrl.replace(/^data:image\/png;base64,/, "");
3102
+ buffer = Buffer.from(base64, "base64");
3103
+ } else {
3104
+ throw new Error("Unsupported canvas type for screenshot");
3105
+ }
3106
+ await fs.mkdir(path.dirname(filepath), { recursive: true });
3107
+ await fs.writeFile(filepath, buffer);
3108
+ }
3109
+ async function compareScreenshot(canvas, baselinePath) {
3110
+ try {
3111
+ await fs.access(baselinePath);
3112
+ } catch {
3113
+ console.warn(`Baseline not found at ${baselinePath}, saving current as baseline.`);
3114
+ await takeScreenshot(canvas, baselinePath);
3115
+ return true;
3116
+ }
3117
+ const baselineBuffer = await fs.readFile(baselinePath);
3118
+ const baselineImage = new Image2();
3119
+ baselineImage.src = baselineBuffer;
3120
+ const width = baselineImage.width;
3121
+ const height = baselineImage.height;
3122
+ let currentBuffer;
3123
+ if ("toBuffer" in canvas && typeof canvas.toBuffer === "function") {
3124
+ currentBuffer = canvas.toBuffer("image/png");
3125
+ } else if ("toDataURL" in canvas) {
3126
+ const dataUrl = canvas.toDataURL("image/png");
3127
+ currentBuffer = Buffer.from(dataUrl.replace(/^data:image\/png;base64,/, ""), "base64");
3128
+ } else {
3129
+ throw new Error("Unsupported canvas type");
3130
+ }
3131
+ if (baselineBuffer.equals(currentBuffer)) {
3132
+ return true;
3133
+ }
3134
+ const baselineCanvas = new Canvas3(width, height);
3135
+ const ctx = baselineCanvas.getContext("2d");
3136
+ ctx.drawImage(baselineImage, 0, 0);
3137
+ const baselineData = ctx.getImageData(0, 0, width, height).data;
3138
+ const currentImage = new Image2();
3139
+ currentImage.src = currentBuffer;
3140
+ if (currentImage.width !== width || currentImage.height !== height) {
3141
+ console.error(`Dimension mismatch: Baseline ${width}x${height} vs Current ${currentImage.width}x${currentImage.height}`);
3142
+ return false;
3143
+ }
3144
+ const currentCanvas = new Canvas3(width, height);
3145
+ const ctx2 = currentCanvas.getContext("2d");
3146
+ ctx2.drawImage(currentImage, 0, 0);
3147
+ const currentData = ctx2.getImageData(0, 0, width, height).data;
3148
+ let diffPixels = 0;
3149
+ const totalPixels = width * height;
3150
+ for (let i = 0; i < baselineData.length; i += 4) {
3151
+ if (baselineData[i] !== currentData[i] || // R
3152
+ baselineData[i + 1] !== currentData[i + 1] || // G
3153
+ baselineData[i + 2] !== currentData[i + 2] || // B
3154
+ baselineData[i + 3] !== currentData[i + 3]) {
3155
+ diffPixels++;
3156
+ }
3157
+ }
3158
+ if (diffPixels > 0) {
3159
+ console.error(`Visual regression: ${diffPixels} pixels differ (${(diffPixels / totalPixels * 100).toFixed(2)}%)`);
3160
+ return false;
3161
+ }
3162
+ return true;
3163
+ }
3092
3164
  function compareScreenshots(baseline, current, threshold = 0.01) {
3093
3165
  if (baseline.length !== current.length) {
3094
3166
  return { diffPercentage: 1 };
@@ -3103,7 +3175,6 @@ function compareScreenshots(baseline, current, threshold = 0.01) {
3103
3175
  const diffPercentage = diffPixels / totalPixels;
3104
3176
  return {
3105
3177
  diffPercentage
3106
- // Generating a diff image buffer would require a library like pixelmatch
3107
3178
  };
3108
3179
  }
3109
3180
  function createVisualTestScenario(sceneName) {
@@ -3125,6 +3196,7 @@ export {
3125
3196
  captureCanvasDrawCalls,
3126
3197
  captureGameScreenshot,
3127
3198
  captureGameState,
3199
+ compareScreenshot,
3128
3200
  compareScreenshots,
3129
3201
  createBandwidthTestScenario,
3130
3202
  createBinaryStreamMock,
@@ -3249,6 +3321,7 @@ export {
3249
3321
  simulateServerTick,
3250
3322
  simulateSnapshotDelivery,
3251
3323
  stairTrace,
3324
+ takeScreenshot,
3252
3325
  teardownBrowserEnvironment,
3253
3326
  teardownMockAudioContext,
3254
3327
  teardownNodeEnvironment,