bench-telemetry
Skill9 starsChanged 4 months agoMITView on GitHub
The REQUIRED window.__bench telemetry contract — getState, reset, getPlayerPosition, getCameraInfo, getEntities, getObjectiveStatus — with the exact shape to implement. Games without it are score-capped.
In this repository6 other files it gives its agents.
- game-qualitySkill
- playtestSkill
- prdSkill
- subagentsSkill
- threejs-gameSkill
- world-designSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 85
All six methods exist and are functions on window.__bench.
- Distinctive: line 86
Every method returns synchronously with JSON-serializable data (no Promises).
- Distinctive: line 87
No method throws, in any game phase (menu, playing, won, lost).
- Very specific: line 94
Test the contract yourself with the test_game tool — its report has a bench_contract section showing exactly which methods were found and …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
The window.__bench Telemetry Contract (REQUIRED)
Your game is scored by scripted probes that call window.__bench. If the
object or any method is missing, the Playability Score is capped and the World Coherence
Score cannot be earned. Implement it early — it is a few lines once your gameState
exists — and keep it working as the game grows.
Exact shape
Attach this in your main module after the game initializes:
// js/bench.js (or inline in main.js) — wire to your real gameState
import * as THREE from 'three'; // already mapped by the scaffold's import map
export function installBench(gameState, player, camera, restartGame) {
window.__bench = {
// Full serializable snapshot of the game state. Plain data only —
// no THREE objects, no functions, no cycles (it must survive JSON.stringify).
getState() {
return {
phase: gameState.phase, // 'menu' | 'playing' | 'won' | 'lost'
score: gameState.score,
health: gameState.player.health,
entities: gameState.entities.length,
};
},
// Restart to the initial state (same as the player pressing Restart).
// After reset(), getState() and getPlayerPosition() must return values
// matching a fresh load.
reset() {
restartGame();
},
// World-space player position as {x, y, z} finite numbers.
// Return the controlled avatar/object root (or the camera focus point if
// that better represents "where the player is").
getPlayerPosition() {
const p = player.root.position;
return { x: p.x, y: p.y, z: p.z };
},
// Camera position + look direction, finite numbers.
getCameraInfo() {
const dir = new THREE.Vector3();
camera.getWorldDirection(dir);
return {
position: { x: camera.position.x, y: camera.position.y, z: camera.position.z },
direction: { x: dir.x, y: dir.y, z: dir.z },
fov: camera.fov,
};
},
// Every live gameplay entity (NPCs, pickups, interactables, etc.).
// Empty array is valid when nothing is alive.
getEntities() {
return gameState.entities.map((e) => ({
id: e.id,
kind: e.kind, // short string label for the entity type
position: { x: e.root.position.x, y: e.root.position.y, z: e.root.position.z },
}));
},
// Progress toward the win condition, plus the outcome flags.
getObjectiveStatus() {
return {
objective: 'complete the objective', // human-readable current objective
progress: gameState.progress, // 0..1 fraction toward win
won: gameState.phase === 'won',
lost: gameState.phase === 'lost',
};
},
};
}Rules the probes check
- All six methods exist and are functions on
window.__bench. - Every method returns synchronously with JSON-serializable data (no Promises).
- No method throws, in any game phase (menu, playing, won, lost).
getPlayerPosition()returns finite{x, y, z}— no NaN, no infinite falling (y should not run away to -infinity).- The camera stays within a sane distance of the player.
- The state returned by
getState()evolves over time while playing, andreset()genuinely restores the initial state and position.
Test the contract yourself with the test_game tool — its report has a
bench_contract section showing exactly which methods were found and what each
returned.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

