feat(game): add neon isometric relay interface

This commit is contained in:
Hermes Agent
2026-07-28 09:18:02 +08:00
parent 8e5631f74a
commit c53bc26d7d
7 changed files with 917 additions and 1 deletions
+48
View File
@@ -0,0 +1,48 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { LEVELS, canReachTarget } from '../levels.js';
import { parseLevel } from '../game-engine.js';
test('every authored relay has reachable signal pads before any echo is anchored', () => {
for (const definition of LEVELS) {
const level = parseLevel(definition.map);
for (const [padId, position] of level.pads) {
assert.equal(
canReachTarget(level, position, new Set()),
true,
`${definition.id}: pad ${padId} should be initially reachable`,
);
}
}
});
test('each relay keeps extraction sealed until its full gate sequence is sustained', () => {
for (const definition of LEVELS) {
const level = parseLevel(definition.map);
const allGates = new Set(level.gates.keys());
assert.equal(
canReachTarget(level, level.goal, new Set()),
false,
`${definition.id}: extraction must not be reachable with all gates closed`,
);
assert.equal(
canReachTarget(level, level.goal, allGates),
true,
`${definition.id}: extraction should be reachable with all gates active`,
);
}
});
test('multi-gate relays preserve their intended staged locks', () => {
const double = parseLevel(LEVELS.find((level) => level.id === 'prism-drift').map);
const triple = parseLevel(LEVELS.find((level) => level.id === 'cathedral-null').map);
assert.equal(canReachTarget(double, double.goal, new Set(['A'])), false);
assert.equal(canReachTarget(double, double.goal, new Set(['A', 'B'])), true);
assert.equal(canReachTarget(triple, triple.goal, new Set(['A'])), false);
assert.equal(canReachTarget(triple, triple.goal, new Set(['A', 'B'])), false);
assert.equal(canReachTarget(triple, triple.goal, new Set(['A', 'B', 'C'])), true);
});
+22
View File
@@ -0,0 +1,22 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
const root = new URL('../', import.meta.url);
const readProjectFile = (name) => readFileSync(new URL(name, root), 'utf8');
test('the playable shell uses a local canvas entry point and no external runtime assets', () => {
const html = readProjectFile('index.html');
assert.match(html, /<canvas[^>]+id="relay-canvas"/);
assert.match(html, /<script\s+type="module"\s+src="\.\/app\.js"><\/script>/);
assert.match(html, /data-action="anchor"/);
assert.doesNotMatch(html, /<(?:script|link|img)\b[^>]+(?:src|href)\s*=\s*["']https?:\/\//i);
});
test('the runtime exposes a narrow smoke-test surface without network calls', () => {
const app = readProjectFile('app.js');
assert.match(app, /window\.__VANTA_TEST__/);
assert.doesNotMatch(app, /\bfetch\s*\(|XMLHttpRequest|WebSocket/);
});