Write fast, auto-retrying, multi-client game tests in TypeScript powered by Playwright and native Unreal Engine telemetry.

Specter replaces brittle C++ Gauntlet scripts with type-safe TypeScript and native Unreal Engine telemetry.
Engine-aware auto-retrying matchers like expect(actor).toHavePropertyValue('Health', 0) that eliminate flaky setTimeout sleeps.
Direct C++ subsystem hooks to trigger Gameplay Abilities, inspect tags (toHaveGameplayTag), check effects, and evaluate AI behavior trees.
Simulate real-world network conditions directly from code using setEmulatedLatency(150) and setPacketLoss(5).
Stream 60 FPS analog thumbstick vectors (injectAxis), joystick circles, sweeps, and fighting game combos with microsecond precision.
Orchestrate a Dedicated Server alongside an arbitrary number of game clients (client1, client2, client3...) simultaneously inside a single Playwright test script.
Render 3D cyan bounding boxes and state labels (actor.highlight("Phase 2")) directly inside your level viewport during live test execution.

No context switching. Specter parses your Playwright suite directly inside an Unreal Editor Utility Widget with real-time test execution controls and live step telemetry.
Parses Playwright test files directly into an in-editor TreeView with live pass/fail/running status badges and instant rerun triggers.
Click any failing test node or assertion step inside the Unreal Editor to jump directly to the exact file and line number in VS Code.
Watch Playwright steps execute frame-by-frame in real-time with green/red status indicators and live console log streaming inside PIE.
Inspect historical property changes, GAS attribute fluctuations, and gameplay tag updates on a visual, frame-accurate timeline.
Games are asynchronous environments. Specter introduces engine-aware auto-retrying assertions that listen to state events and eliminate brittle manual delays.
expect(actor).toHavePropertyValue('Health', 0) and expect(actor).toBeVisible() poll/listen to engine ticks until conditions pass.
Captures automated viewport screenshots, console logs, and action timelines directly into standard Playwright HTML test reports.
import { test, expect } from '@specter/test';
test('Boss health drops on impact', async ({ world }) => {
const boss = world.actor('BP_Boss_C');
// Triggers damage event
await world.actor('BP_Player').pressKey('SpaceBar');
// Engine-Aware Assertion: Auto-retries until condition is met
await expect(boss).toHavePropertyValue('Health', 0, {
operator: '<=',
timeout: 5000
});
// Asserts UMG visibility
await expect(world.widget('WBP_VictoryScreen')).toBeVisible();
});Locate 3D Actors and UMG Widgets effortlessly across complex levels using class names, tags, components, and spatial proximity.
for...of loop iteration.Bypass coarse digital keystrokes. Specter lets you stream 60 FPS analog thumbstick vectors, 2D/3D Action Vectors, and parametric mathematical curves directly to Unreal Engine 5's Enhanced Input Actions (UInputAction / IA_Move) and native input subsystems.
IA_Move) or custom parametric mathematical curves (addParametricCurve) with frame-accurate timing.SpecterInputSequence to generate 60 FPS joystick circles (addAxisCircle), parametric sweeps, and fighting game combos.down(), up(), duration-based pressKey('E', 2000), and analog trigger sweeps.import { test, expect, SpecterInputSequence } from '@specter/test';
test('Simultaneous parametric movement curves on 3 clients', async ({ world, client2, client3 }) => {
const p1 = world.actor(GameAssets.Characters.Marshmallow).isLocallyControlled();
const p2 = client2.actor(GameAssets.Characters.Marshmallow).isLocallyControlled();
const p3 = client3.actor(GameAssets.Characters.Marshmallow).isLocallyControlled();
// Pattern 1: True Dual-Loop Figure-Eight
const fig8Seq = new SpecterInputSequence().addParametricCurve((progress) => {
const currentProgress = (progress * 2) % 1.0;
const theta = (currentProgress / 0.5) * Math.PI * 2;
return {
actions: {
IA_Move: {
x: currentProgress < 0.5 ? Math.sin(theta) : -Math.sin(theta),
y: Math.cos(theta)
}
}
};
}, 0, 4000, 30);
// Pattern 2: Smooth Zig-Zag Wave
const zigZagSeq = new SpecterInputSequence().addParametricCurve((progress) => {
const currentProgress = (progress * 2) % 1.0;
return {
actions: {
IA_Move: {
x: Math.cos(currentProgress * Math.PI * 16) * 1.25,
y: Math.sin(currentProgress * Math.PI * 2)
}
}
};
}, 0, 4000, 30);
// Pattern 3: Straight Back and Forth
const backAndForthSeq = new SpecterInputSequence().addParametricCurve((progress) => {
const currentProgress = (progress * 2) % 1.0;
return { actions: { IA_Move: { x: 0.0, y: Math.sin(currentProgress * Math.PI * 2) } } };
}, 0, 4000, 30);
// Play all 3 sequences SIMULTANEOUSLY across 3 clients
await Promise.all([
p1.playSequence(fig8Seq),
p2.playSequence(zigZagSeq),
p3.playSequence(backAndForthSeq)
]);
});Built specifically for Unreal Engine. Specter integrates directly into GAS, AI Behavior Trees, and Animation Skeleton Montages out of the box.
Trigger abilities directly by Gameplay Tag (triggerAbilityByTag), inspect active tags (toHaveGameplayTag), check Gameplay Effects, and assert attribute sets.
Inspect AI Controllers, assert Blackboard values (toHaveBlackboardValue), evaluate StateTrees, and verify line-of-sight checks (hasLineOfSightTo).
Verify AnimMontage playback states (isPlayingMontage), active animation sections, and listen for AnimNotifies during combat execution.
import { test, expect } from '@specter/test';
test('Hero casts ultimate and triggers AI flee state', async ({ world }) => {
const hero = world.actor('BP_Hero_Steel');
const enemyAI = world.actor('BP_Enemy_AI');
// Trigger GAS Ability by Gameplay Tag
await hero.triggerAbilityByTag('Ability.Hero.Ultimate');
// Assert Gameplay Tag presence & Blackboard state
await expect(hero).toHaveGameplayTag('State.Casting');
await expect(enemyAI).toHaveBlackboardValue('BehaviorState', 'Flee');
// Assert AnimMontage playback section
await expect(hero).isPlayingMontage('AM_Steel_Slam', { section: 'Impact' });
});Test Dedicated Servers and multiple client viewports simultaneously inside a single Playwright script. Specter makes multiplayer replication testing painless.
createWorld({ launchClient: true }) to spin up and control multiple client viewports on distinct ports.setEmulatedLatency(150) and setPacketLoss(5).test('Replication under lag', async ({ world, client1, client2 }) => {
// Simulate 150ms ping & 5% packet loss on Client 1
await client1.network.setEmulatedLatency(150);
await client1.network.setPacketLoss(5);
// Client 1 (Steel) attacks Client 2 (Enemy)
await client1.actor('BP_Hero_Steel').pressKey('Q');
// Server authority verification and client replication on enemy
await expect(client2.actor('BP_Hero_Enemy')).toHavePropertyValue('Health', 80);
await expect(world.actor('BP_Hero_Enemy')).toHavePropertyValue('Health', 80);
});Never guess what an actor is doing in PIE. Calling actor.highlight("Phase 2") renders 3D cyan bounding boxes, state labels, and visual assertion overlays directly inside your level viewport during live test execution.
Book a 1-on-1 technical walkthrough or inquire about our 30-Day Studio Proof of Concept ($2,500).