Audience: NeuroCompute engineers and coding agents implementing the server side of Appleseed integration.
Appleseed side: already ships the client bridge at /game/neurocompute-appleseed.js.
Your job: host the orchestration script, API routes, storage, and LLM loop described below.
/game/neurocompute-backend-guide.html/index.html| Layer | Owner | Responsibility |
|---|---|---|
| Appleseed (browser) | This repo | Simulation, canvas, AppleseedAgentBridge, snapshots, deterministic mode, lifeforms |
| NC integration script | NeuroCompute | Patron linking, score POST, action polling, analytics wiring, launch helpers |
| NC API + DB | NeuroCompute | Persistence, leaderboard, world-map enrichment, LLM decisions, verification |
Want to try the stack locally before building production APIs?
Run node game/test-agent-server.mjs and open
agent-playground.html to test forged worlds with preset seeds
(wetlands, fungal web, arid symbiosis, lifeform lab, etc.).
POST /api/game/appleseed/analytics (LLM play tracking)POST /api/game/appleseed/action (LLM decision loop)/game/neurocompute-appleseed.js on neurocompute.me (orchestration layer)POST /api/game/appleseed/score + game_scores tableGET /api/game/appleseed/leaderboardbiodiversityScorePOST + GET /api/game/appleseed/snapshot/:id)POST /api/game/appleseed/verify-biodiversity (anti-cheat for best-state records)Serve a script at:
https://neurocompute.me/game/neurocompute-appleseed.js
Appleseed loads it when the game page sets:
window.ncScriptUrl = "https://neurocompute.me/game/neurocompute-appleseed.js";
window.ncPatronToken = "<patron-secret>";
window.ncRegionX = 16;
window.ncRegionY = 16;
window.ncLLMControl = true;
window.ncAnalyticsUrl = "https://neurocompute.me/api/game/appleseed/analytics";
window.ncAnalyticsModel = "local-llm-7b";
window.ncNodeName = "compute-node-3";
Minimum responsibilities of that script:
window.AppleseedAgentBridgebridge.startRun({ ... }) with world/agent/analytics configPOST /api/game/appleseed/action when ncLLMControl is truebridge.applyAction(action)(function () {
const ACTION_POLL_MS = 3000;
function waitForBridge() {
return new Promise((resolve) => {
if (window.AppleseedAgentBridge) return resolve(window.AppleseedAgentBridge);
const timer = setInterval(() => {
if (window.AppleseedAgentBridge) {
clearInterval(timer);
resolve(window.AppleseedAgentBridge);
}
}, 100);
});
}
async function pollAction(bridge) {
if (!window.ncLLMControl) return;
const state = bridge.getState();
const res = await fetch("/api/game/appleseed/action", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + (window.ncPatronToken || "")
},
body: JSON.stringify({
state,
agent: bridge.getActiveAgentName(),
worldId: state.worldId,
region: state.region
})
});
if (!res.ok) return;
const action = await res.json();
if (action && action.type) bridge.applyAction(action);
}
waitForBridge().then((bridge) => {
bridge.startRun({
worldId: "world-" + (window.ncRegionX || 0) + "-" + (window.ncRegionY || 0),
regionX: window.ncRegionX,
regionY: window.ncRegionY,
llmControl: !!window.ncLLMControl,
activeAgentName: window.ncActiveAgentName || "NC-Agent",
analytics: window.ncAnalyticsUrl ? {
enabled: true,
endpoint: window.ncAnalyticsUrl,
model: window.ncAnalyticsModel,
nodeName: window.ncNodeName
} : undefined,
autoSubmitScore: { enabled: true, onlyWhenLlmControl: true, everyMs: 45000 }
});
setInterval(() => pollAction(bridge), ACTION_POLL_MS);
});
})();
Route: POST /api/game/appleseed/analytics
Appleseed auto-POSTs when configureAnalytics({ endpoint }) or window.ncAnalyticsUrl is set.
{
"event": "action_applied",
"timestamp": 1735689600123,
"context": {
"gameId": "appleseed",
"sessionId": "sess-m5abc123-xyz",
"runId": "run-m5def456-abc",
"worldId": "world-eu-16-16",
"worldSeed": "WORLD-EU-16-16",
"region": { "x": 16, "y": 16, "cellSize": 128 },
"activeAgentName": "Scout-Alpha",
"llmControl": true,
"model": "local-llm-7b",
"nodeName": "compute-node-3",
"simulationSpeed": 6,
"deterministic": true
},
"payload": { "...event-specific fields..." },
"state": { "...full getState() on key events only..." }
}
| event | When | Notes |
|---|---|---|
run_started | LLM run boot | Includes state |
action_applied | Every bridge action | High volume — index by runId |
score_submitted | Manual or auto score | Includes state |
score_auto_submitted | Auto-submit interval | Includes state |
snapshot_created | Checkpoint saved | Includes state |
disaster_started | Storm/drought/fire | |
lifeform_spawned | Custom species spawn | |
lifeform_unlocked | Apple-gated unlock | |
active_agent_changed | Agent rename |
game_analytics_eventsid UUID PRIMARY KEY
event TEXT NOT NULL
session_id TEXT NOT NULL
run_id TEXT
world_id TEXT
region_x INT
region_y INT
agent_name TEXT
model TEXT
node_name TEXT
llm_control BOOLEAN
payload_json JSONB
state_json JSONB
created_at TIMESTAMPTZ DEFAULT now()
-- indexes
CREATE INDEX idx_analytics_session ON game_analytics_events(session_id);
CREATE INDEX idx_analytics_run ON game_analytics_events(run_id);
CREATE INDEX idx_analytics_agent ON game_analytics_events(agent_name) WHERE llm_control = true;
{ "ok": true }
Return 200 quickly. Use async workers for heavy processing.
Route: POST /api/game/appleseed/action
Called every ~3s by the NC integration script while ncLLMControl=true.
{
"state": { "...full AppleseedAgentBridge.getState()..." },
"agent": "Scout-Alpha",
"worldId": "world-eu-16-16",
"region": { "x": 16, "y": 16 }
}
Authenticate with patron token (Authorization: Bearer <token> or body field).
{ "type": "plant_seed" }
{ "type": "release_bird" }
{ "type": "release_bunny" }
{ "type": "release_fox" }
{ "type": "release_bear" }
{ "type": "release_bee" }
{ "type": "release_butterfly" }
{ "type": "harvest_apples" }
{ "type": "move_to", "x": 420, "y": 310 }
{ "type": "set_simulation_speed", "multiplier": 6 }
{ "type": "trigger_disaster", "disasterType": "storm", "intensity": 1.2 }
{ "type": "register_lifeform", "definition": { "id": "proto_algae", "label": "Proto Algae", ... } }
{ "type": "spawn_lifeform", "lifeformId": "proto_algae", "x": 200, "y": 150 }
{ "type": "create_snapshot", "metadata": { "reason": "llm_checkpoint" } }
Full action list: see Client Bridge API.
set_simulation_speed for fast-forward experimentsIf LLM times out, return a heuristic action (e.g. plant_seed if trees < 3, else release_bee).
Route: POST /api/game/appleseed/score
{
"patronToken": "...",
"regionX": 16,
"regionY": 16,
"worldId": "world-eu-16-16",
"activeAgentName": "Scout-Alpha",
"score": 144,
"biodiversity": {
"speciesTypesPresent": 6,
"livingCreatures": 24,
"eggsCollected": 1,
"counts": {
"trees": 5, "birds": 2, "bunnies": 3, "foxes": 1,
"bears": 0, "bees": 4, "butterflies": 2, "flowers": 8
}
},
"llmControl": true,
"model": "local-llm-7b",
"nodeName": "compute-node-3"
}
game_scoresid, patron_id, world_id, region_x, region_y, score, biodiversity_json,
agent_name, llm_control, model, node_name, created_at
Route: GET /api/game/appleseed/leaderboard?limit=20®ionX=16®ionY=16
{
"entries": [
{
"patronId": "...",
"displayName": "Scout-Alpha",
"score": 144,
"regionX": 16,
"regionY": 16,
"worldId": "world-eu-16-16",
"biodiversity": { "...": "..." },
"createdAt": "2026-05-24T12:00:00Z"
}
]
}
Each map cell should expose the best biodiversity score played in that region:
{
"x": 16,
"y": 16,
"biodiversityScore": 144,
"bestAgentName": "Scout-Alpha",
"bestWorldId": "world-eu-16-16",
"lastPlayedAt": "2026-05-24T12:00:00Z"
}
Update on score POST when new score > cell best.
Upload: POST /api/game/appleseed/snapshot
Load: GET /api/game/appleseed/snapshot/:id
Wire from Appleseed via:
bridge.setSnapshotPublisher(async (snapshot) => {
const res = await fetch("/api/game/appleseed/snapshot", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(snapshot)
});
return res.json(); // { ok: true, id: "snap-...", publicUrl: "..." }
});
On neurocompute.me, link “Load world” to:
/index.html?ncRunConfig={"snapshotId":"snap-abc","worldId":"world-eu-16-16","llmControl":true}
Client state is not trusted for leaderboards. Appleseed supports server attestation:
bridge.setBestBiodiversityVerifier(async ({ candidate, snapshot, state, actionLog }) => {
const res = await fetch("/api/game/appleseed/verify-biodiversity", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ candidate, snapshot, state, actionLog })
});
return res.json(); // { ok: true, source: "server", attestation: "signed-proof" }
});
Open Appleseed in a new tab with full LLM + analytics wiring:
https://<appleseed-host>/index.html
?worldId=world-eu-16-16
®ionX=16
®ionY=16
&llm=1
&speed=6
&agent=Scout-Alpha
&model=local-llm-7b
&node=compute-node-3
&analytics=1
&analyticsUrl=https://neurocompute.me/api/game/appleseed/analytics
Or hand off via localStorage:
bridge.setPendingRunConfig({ worldId, llmControl: true, analytics: { enabled: true, endpoint: "..." } });
window.open("https://<appleseed-host>/index.html", "_blank");
A session is LLM-driven when all of these are true:
context.llmControl === true on analytics eventscontext.activeAgentName is set (not null)action_applied events with same runIdQuery example:
SELECT run_id, agent_name, model, node_name, COUNT(*) AS actions
FROM game_analytics_events
WHERE event = 'action_applied' AND llm_control = true
GROUP BY run_id, agent_name, model, node_name
ORDER BY MAX(created_at) DESC;
/game/neurocompute-appleseed.js — bridge source in this repo/index.html — game entry point
Security: Never trust client-reported best scores without verify-biodiversity.
Treat patron tokens as secrets. Rate-limit /action and /analytics per patron/session.