Module Lambda: Wormholes — Implementation Summary
Date: 2026-07-12
Status: ✅ Complete — Engine + Tests + UI
Classification: Warped (exhibition only, predicted ~50-60% skill preservation)
Overview
Module Lambda (Wormholes) introduces spatial topology manipulation as a game mechanic. When a captain plays a double on the Neutral Zone, their personal Warp Trail swaps with the Neutral Zone, fundamentally altering board state ownership.
This creates hostile takeover dynamics where one captain’s investment becomes another’s prize, and provides escape pod strategies for captains stuck with dead-end trails.
Implementation Complete
1. Engine (warp12-engine) ✅
Files Modified:
libs/engine/src/lib/types/modules.ts- AddedWormholesModuleinterface and configlibs/engine/src/lib/engine/apply-action.ts- AddedexecuteWormholeSwap()function and integrationlibs/engine/src/lib/ai/module-calibration.spec.ts- Added Lambda configs for testing
Core Logic (apply-action.ts):
function executeWormholeSwap(round: RoundState, playerId: string): RoundState {
// Swap captain's trail with Neutral Zone
// Destroy distress beacon during transit (fresh start)
// Return updated round state
}
Trigger Conditions:
- Module Lambda is enabled (
modules.wormholes.enabled) - Player charts a double onto the Neutral Zone
- Swap occurs after the double is placed on NZ
- Red Alert is then triggered on the captain’s newly acquired trail
Mechanics:
- Player’s trail tiles → Neutral Zone
- Neutral Zone tiles → Player’s trail
- Distress beacon on player’s trail is destroyed
- Red Alert responsibility is on the player’s new trail (which now contains the double)
2. Tests ✅
Test File: libs/engine/src/lib/engine/wormhole.spec.ts
Test Coverage (6 tests, all passing):
- ✅ Swaps captain trail with neutral zone when double played on NZ
- ✅ Triggers red alert on newly acquired trail after swap
- ✅ Destroys distress beacon during wormhole transit
- ✅ Does not trigger wormhole when module disabled
- ✅ Only triggers wormhole on doubles, not regular tiles
- ✅ Hostile takeover scenario - stealing built neutral zone
Run Tests:
yarn test:engine --run wormhole.spec.ts
3. UI/React (warp12-react) ✅
Files Modified:
libs/react/src/hand/game-log.ts- Added wormhole effect detection and message
Game Log Integration:
- Added
'wormhole-opened'toGameLogEffecttype - Detection: Checks trail length changes before/after double play on NZ
- Message:
"opening a Wormhole — trail swapped with the Neutral Zone"
Example Log Output:
Armstrong charts 9-9 onto the Neutral Zone, opening a Wormhole — trail swapped with the Neutral Zone, causing a Red Alert
4. Rules Documentation ✅
Files Updated:
RULES.md- Added Module Lambda section (after Kappa, before Epsilon)RULES.tex- Added Module Lambda LaTeX sectiondocs/module-lambda-wormholes-design.md- Complete design document
RULES.md Section:
- Classification: Warped (exhibition only)
- Mechanic description with examples
- Strategic implications (hostile takeover, escape pod, risk assessment)
- Tactical impact analysis
- Status: Exhibition/Warped mode only, predicted ~50-60% skill preservation
How to Use
Enable in Game Setup
const game = createLobbyState({
id: 'wormhole-test',
captains: [...],
modules: {
wormholes: true,
},
});
Gameplay
- Build up your Warp Trail (or let opponents build up the Neutral Zone)
- When you have a double matching the Neutral Zone’s open value
- Play the double on the Neutral Zone
- Wormhole opens: Your trail and NZ swap ownership
- Red Alert triggers on your new trail — you must satisfy it
- If you can’t satisfy the Red Alert, you deploy a beacon on your new trail
Strategic Considerations
Offensive: Hostile Takeover
Scenario: Opponent has built a long, valuable trail
Strategy: Play double on Neutral Zone to steal their progress
Risk: Must be able to answer the Red Alert on the stolen trail
Defensive: Escape Pod
Scenario: Your trail is blocked with dead doubles and high pips
Strategy: Dump your disaster into the public Neutral Zone
Result: Fresh start with whatever was on the NZ
Risk Management
Before opening a Wormhole:
- ✅ Can you answer the Red Alert after the swap?
- ✅ Is the Neutral Zone better than your current trail?
- ✅ Will your old trail help or hurt opponents when it becomes public?
Technical Details
Red Alert Handling After Wormhole
The trickiest part of the implementation was handling Red Alert correctly after a wormhole swap:
Problem: When a double is played on neutral-zone, the engine creates a Red Alert with trailPlayerId = '' (empty, meaning it’s on the public NZ). But after a wormhole, that double is now on the captain’s private trail.
Solution:
- Added
wormholeSwappedboolean parameter toresolvePostChartAnomalies() - When wormhole occurred, set
trailPlayerId = playerIdinstead of empty string - This ensures Red Alert responsibility is correctly assigned to the captain’s new trail
Module Detection in Game Log
Challenge: How to detect that a wormhole occurred from before/after state?
Solution: Compare trail and NZ lengths before and after the action:
const wormholeOpened =
isDouble(coordinate) &&
route.kind === 'neutral-zone' &&
(afterTrailLength ≈ beforeNzLength + 1) && // Player got NZ + double
(afterNzLength ≈ beforeTrailLength); // NZ got player's old trail
Calibration Status
Module Lambda is included in the calibration matrix as:
warped-lambda(Lambda only)warped-ultimate(all warped modules: Iota + Kappa + Lambda)
Expected Skill Preservation: ~50-60%
Rationale: High-skill players invest in long-term trail building, which Lambda punishes via theft risk. Lower-skill players benefit from the randomness of dynamic ownership changes.
Run Calibration:
MODULE_CALIBRATION_GAMES=500 yarn calibrate:modules
Build & Test Commands
# Build engine with Lambda support
yarn build:engine
# Run wormhole tests
yarn test:engine --run wormhole.spec.ts
# Build React lib with game log support
yarn build:react
# Build Bridge app
yarn build:bridge
# Full calibration (includes Lambda)
MODULE_CALIBRATION_GAMES=500 yarn calibrate:modules
Future Enhancements
Potential Additions
- Visual Animation: Animate the trail swap in the UI
- Confirmation Dialog: “Open Wormhole? Your trail will become public.”
- AI Heuristics: Add
wormholeOpportunityandwormholeDefenseheuristics - Sound Effect: Unique sound for wormhole opening
- Statistics: Track wormhole usage in match stats
Open Design Questions
- Should there be a limit on wormholes per round? (Currently unlimited)
- Should wormholes work with active Subspace Fractures? (Currently yes, fracture travels with the trail)
- Should wormholes be available in go-out objective? (Currently yes, creates chaos)
References
- Design Doc:
/Volumes/Code/Warp12/docs/module-lambda-wormholes-design.md - Rules:
/Volumes/Code/Warp12/RULES.md(Module Lambda section) - Engine:
/Volumes/Code/Warp12/libs/engine/src/lib/engine/apply-action.ts - Tests:
/Volumes/Code/Warp12/libs/engine/src/lib/engine/wormhole.spec.ts - UI:
/Volumes/Code/Warp12/libs/react/src/hand/game-log.ts
Completion Checklist
- Module type definition (
WormholesModule) - Engine swap logic (
executeWormholeSwap) - Red Alert handling after swap
- Distress beacon destruction
- Unit tests (6 tests, all passing)
- Game log integration
- RULES.md documentation
- RULES.tex documentation
- Calibration config added
- Builds successfully (engine + react + bridge)
- Implementation summary document
Status: Ready for playtesting! 🚀