@polycode-projects/the-mechanical-code-talker 5.0.3 → 5.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/worlds/manifest.json +9 -9
- package/corpus/worlds/shards/town-square-chapel.jsonl.gz +0 -0
- package/corpus/worlds/shards/town-square-market.jsonl.gz +0 -0
- package/corpus/worlds/shards/town-square.jsonl.gz +0 -0
- package/corpus/worlds/src/town-square-chapel.jsonl +1 -1
- package/corpus/worlds/src/town-square-market.jsonl +1 -1
- package/corpus/worlds/src/town-square.jsonl +1 -1
- package/data/mudiii-assets.json +11 -6
- package/package.json +1 -1
- package/src/domain/game-config.mjs +3 -1
- package/src/domain/spider-fly-world.mjs +11 -13
- package/src/services/mudiii-scene.mjs +131 -39
- package/src/services/mudiii-turn.mjs +82 -1
- package/src/services/mudiii-viz.mjs +16 -6
- package/src/services/spider-fly-viz.mjs +57 -60
- package/src/surfaces/web/memory-ask-browser.bundle.js +64 -64
- package/src/surfaces/web/mudiii-browser-entry.mjs +3 -3
|
@@ -813,6 +813,7 @@ function pageScript() {
|
|
|
813
813
|
const el = (id) => document.getElementById(id);
|
|
814
814
|
let scenarioIndex = 0;
|
|
815
815
|
const scenario = function () { return DATA.scenarios[scenarioIndex]; };
|
|
816
|
+
const gridSizeOf = function () { return scenario().gridSize || DATA.gridSize; };
|
|
816
817
|
const rosterOf = function (s, role) {
|
|
817
818
|
return (s.agents || []).filter(function (a) { return !role || a.role === role; }).map(function (a) { return a.id; });
|
|
818
819
|
};
|
|
@@ -881,6 +882,9 @@ function pageScript() {
|
|
|
881
882
|
|
|
882
883
|
function applyTickResult(result) {
|
|
883
884
|
if (!result) return;
|
|
885
|
+
// The engine owns the count. Anything that advances a turn — the deck, a
|
|
886
|
+
// chat frame — lands here, so the page never keeps a rival tally.
|
|
887
|
+
if (typeof result.turn === "number") globalTurn = result.turn;
|
|
884
888
|
if (result.agents) agentsById = result.agents;
|
|
885
889
|
if (result.items) itemsById = result.items;
|
|
886
890
|
callScene("applyTick", { agents: result.agents, items: result.items, ecology: result.ecology });
|
|
@@ -892,8 +896,7 @@ function pageScript() {
|
|
|
892
896
|
async function runOneTick() {
|
|
893
897
|
return serializeTick(async function () {
|
|
894
898
|
if (!session) return null;
|
|
895
|
-
|
|
896
|
-
const result = await session.tick(globalTurn);
|
|
899
|
+
const result = await session.tick();
|
|
897
900
|
applyTickResult(result);
|
|
898
901
|
renderAll();
|
|
899
902
|
return result;
|
|
@@ -921,8 +924,16 @@ function pageScript() {
|
|
|
921
924
|
function sendCommand(line) {
|
|
922
925
|
appendChat("u", line);
|
|
923
926
|
if (!session) { appendChat("a", "no session is open yet \\u2014 reset to start one."); return Promise.resolve(); }
|
|
924
|
-
|
|
927
|
+
// A chat line can run a real turn. An addressed told-fact does, and the
|
|
928
|
+
// visitor should watch the lie land, so the board is read back in the same
|
|
929
|
+
// queue slot. board() spends no turn, so a line that ran none costs
|
|
930
|
+
// nothing. It reports no goal or plan either, because a resting board has
|
|
931
|
+
// decided nothing, which is the blank boot() already draws at turn 0.
|
|
932
|
+
return serializeTick(async function () {
|
|
933
|
+
const res = await tmct.turn(line);
|
|
934
|
+
const board = await session.board();
|
|
925
935
|
appendChat("a", res.answer);
|
|
936
|
+
applyTickResult(board);
|
|
926
937
|
renderAll();
|
|
927
938
|
return res;
|
|
928
939
|
});
|
|
@@ -1027,7 +1038,7 @@ function pageScript() {
|
|
|
1027
1038
|
|
|
1028
1039
|
// ---- the top-down map panel ---------------------------------------------
|
|
1029
1040
|
function renderMapPanel() {
|
|
1030
|
-
const dots = mapDotsFor(agentsList(), itemsList(),
|
|
1041
|
+
const dots = mapDotsFor(agentsList(), itemsList(), gridSizeOf());
|
|
1031
1042
|
el("mapPanelBoard").innerHTML = dots.map(function (d) {
|
|
1032
1043
|
return '<span class="map-dot map-dot-' + esc(d.kind) + '" style="left:' + d.xPct + '%;top:' + d.yPct + '%" title="' + esc(d.id) + '"></span>';
|
|
1033
1044
|
}).join("");
|
|
@@ -1216,7 +1227,7 @@ function pageScript() {
|
|
|
1216
1227
|
agentsById = {};
|
|
1217
1228
|
itemsById = {};
|
|
1218
1229
|
el("chatInput").disabled = false;
|
|
1219
|
-
await callScene("boot", { propPlacements: props, assetManifest: DATA.assetManifest, gridSize:
|
|
1230
|
+
await callScene("boot", { propPlacements: props, assetManifest: DATA.assetManifest, gridSize: gridSizeOf(), cellSize: 1 });
|
|
1220
1231
|
|
|
1221
1232
|
// The opening board, drawn through the very path a tick takes. Without
|
|
1222
1233
|
// this the page's first sight of where anything stands is the first tick,
|
|
@@ -1225,7 +1236,6 @@ function pageScript() {
|
|
|
1225
1236
|
// the cells both come back from it rather than being guessed here.
|
|
1226
1237
|
const opening = await session.board();
|
|
1227
1238
|
if (seq !== bootSeq) return;
|
|
1228
|
-
globalTurn = opening.turn || 0;
|
|
1229
1239
|
camera.selectedId = Object.keys(opening.agents || {}).sort()[0] || null;
|
|
1230
1240
|
applyTickResult(opening);
|
|
1231
1241
|
renderAll();
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
// spider-fly-viz.mjs — the spider-and-fly full-screen page
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// portable on its own — that reason doesn't apply here).
|
|
1
|
+
// spider-fly-viz.mjs — the spider-and-fly full-screen page: a self-contained
|
|
2
|
+
// document shaped exactly like ledger-viz.mjs/plan-viz.mjs — one inlined <style>
|
|
3
|
+
// (importing viz-theme.mjs's shared tokens), behaviour as an inlined IIFE — but
|
|
4
|
+
// unlike those two, almost nothing is embedded as build-time data: the whole
|
|
5
|
+
// game is LIVE client-side state (spider-fly-browser-entry.mjs's
|
|
6
|
+
// createSpiderFlySession), so renderSpiderFlyHtml only needs the page's own
|
|
7
|
+
// static grid geometry (which never changes) plus a title. The engine, sprite
|
|
8
|
+
// resolver and chat turn engine all arrive via ./spider-fly-browser.bundle.js,
|
|
9
|
+
// referenced with a plain same-origin <script src> — the same sibling-file
|
|
10
|
+
// arrangement index.html already uses for chat-browser.bundle.js (both are the
|
|
11
|
+
// FULL turn engine, both generated fresh per build, neither meant to be
|
|
12
|
+
// committed), not memory-ask-browser.bundle.js's inlined-text arrangement (that
|
|
13
|
+
// bundle is small and inlined specifically so ledger.html stays portable on its
|
|
14
|
+
// own — that reason doesn't apply here).
|
|
16
15
|
//
|
|
17
16
|
// renderSpiderFlyHtml() is pure: no I/O, deterministic output for identical
|
|
18
17
|
// input. scripts/build-demo-site.mjs calls it directly and writes the result
|
|
@@ -125,19 +124,17 @@ export function facingDegreesFor(plan, previousDegrees) {
|
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
/**
|
|
128
|
-
* The updated corpse set for one redraw
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* CORPSE_LINGER_TURNS's own callers elsewhere in this module) passes it
|
|
140
|
-
* explicitly anyway.
|
|
127
|
+
* The updated corpse set for one redraw — visual-only, entirely client-side;
|
|
128
|
+
* the actual starve/eat removal already happened in the engine. Every id
|
|
129
|
+
* present in `prevAgents` but absent from `agents` died THIS tick — eaten or
|
|
130
|
+
* starved are the only two ways an agent ever leaves the engine's own returned
|
|
131
|
+
* roster — and is added at its last-known cell and class; every corpse already
|
|
132
|
+
* older than `lingerTurns` past its own death turn is dropped first, so the set
|
|
133
|
+
* never grows without bound. Returns a plain `{ [id]: { cls, cell, diedAtTurn }
|
|
134
|
+
* }` map. Pure. `lingerTurns` defaults to a literal 4 (not the module-level
|
|
135
|
+
* CORPSE_LINGER_TURNS constant) so this function stays fully `.toString()`-splice
|
|
136
|
+
* safe — every real caller (both the inlined page and CORPSE_LINGER_TURNS's own
|
|
137
|
+
* callers elsewhere in this module) passes it explicitly anyway.
|
|
141
138
|
*/
|
|
142
139
|
export function nextCorpses(prevCorpses, prevAgents, agents, turn, lingerTurns = 4) {
|
|
143
140
|
const out = {};
|
|
@@ -166,9 +163,9 @@ export function nextCorpses(prevCorpses, prevAgents, agents, turn, lingerTurns =
|
|
|
166
163
|
* back to the flat SPRITE_REGISTRY, unchanged from before this module
|
|
167
164
|
* existed).
|
|
168
165
|
* `?preview=1` on the page's own URL switches it into the small, auto-
|
|
169
|
-
* playing, non-interactive mode the home page's hero iframe embeds
|
|
170
|
-
*
|
|
171
|
-
*
|
|
166
|
+
* playing, non-interactive mode the home page's hero iframe embeds — one file
|
|
167
|
+
* serves both the hero and the "open full-screen" link, matching how
|
|
168
|
+
* ledger.html/plan.html are each one file embedded two ways.
|
|
172
169
|
* `engineBundleJs` (the built spider-fly-browser bundle's own text) inlines
|
|
173
170
|
* the engine into the page instead of the sibling `<script src>`, for the
|
|
174
171
|
* CLI's standalone export — one downloadable file that runs from file://
|
|
@@ -344,11 +341,11 @@ ${THEME_TOKENS_CSS}
|
|
|
344
341
|
.hud-id.spider { color: var(--taught); } .hud-id.fly { color: var(--fly); } .hud-id.egg { color: var(--muted); }
|
|
345
342
|
.hud-goal { font-size: .85rem; }
|
|
346
343
|
.hud-plan, .hud-belief { font-family: ${MONO_STACK}; font-size: .66rem; color: var(--muted); margin-top: .25rem; line-height: 1.4; padding-left: .5rem; border-left: 2px solid var(--chrome-accent); }
|
|
347
|
-
/* the click-expand facts panel
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
344
|
+
/* the click-expand facts panel: beside the clicked spider/fly's own row,
|
|
345
|
+
never a separate popover or a second panel elsewhere on the page — the same
|
|
346
|
+
believedCellOf/beliefSnapshotFor read path spider-fly-turn.mjs already
|
|
347
|
+
computes every tick for planning, rendered here as full sentences instead of
|
|
348
|
+
the compact believes:-line above. */
|
|
352
349
|
.hud-detail { flex: 1 1 auto; min-width: 0; font-family: ${MONO_STACK}; font-size: .64rem; line-height: 1.5; color: var(--chrome-well-ink); background: var(--chrome-well); border: 1px solid var(--chrome-edge-lo); box-shadow: var(--chrome-shadow-inset); border-radius: 2px; padding: .35rem .5rem; }
|
|
353
350
|
.hud-detail-title { text-transform: uppercase; letter-spacing: .06em; opacity: .75; margin-bottom: .2rem; }
|
|
354
351
|
/* A stat-readout track: an inset "LCD" well, filled with a segmented pip
|
|
@@ -378,11 +375,11 @@ ${THEME_TOKENS_CSS}
|
|
|
378
375
|
.pill:hover:not(:disabled) { border-color: var(--chrome-accent); }
|
|
379
376
|
.pill:disabled { opacity: .45; cursor: default; }
|
|
380
377
|
.pill[data-role="addr"].active { border-color: var(--taught); color: var(--taught); }
|
|
381
|
-
/* The dynamic deception-pill rail
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
378
|
+
/* The dynamic deception-pill rail: a true/false tag shown ONLY here, via
|
|
379
|
+
border style/color and a small human-facing glyph — the submitted sentence
|
|
380
|
+
itself (data-sentence, filled into #chatq on click) never carries the tag,
|
|
381
|
+
so a clicked pill is indistinguishable from a hand-typed claim once it's in
|
|
382
|
+
the input. */
|
|
386
383
|
.dynpills { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .5rem; padding-top: .5rem; border-top: 1px solid var(--chrome-edge-lo); }
|
|
387
384
|
.dynpills:empty { display: none; padding-top: 0; border-top: none; }
|
|
388
385
|
.pill[data-role="dyn-addr"][data-active="1"] { border-color: var(--taught); color: var(--taught); }
|
|
@@ -745,13 +742,13 @@ ${engineBundleJs ? `<script>\n${embedScriptText(engineBundleJs)}\n</script>` : `
|
|
|
745
742
|
lastAgents = agents;
|
|
746
743
|
}
|
|
747
744
|
|
|
748
|
-
// ---- corpses
|
|
749
|
-
//
|
|
750
|
-
//
|
|
751
|
-
//
|
|
752
|
-
//
|
|
753
|
-
//
|
|
754
|
-
//
|
|
745
|
+
// ---- corpses: visual-only — the actual starve/eat removal already happened
|
|
746
|
+
// in the engine before this redraw ever sees "agents". A corpse sinks to the
|
|
747
|
+
// bottom row of the SAME board column it died in ("drops to the bottom" —
|
|
748
|
+
// spider-fly-world.mjs's own x/y convention, y = GRID_SIZE is the bottom row)
|
|
749
|
+
// and fades out once CORPSE_LINGER_TURNS passes, drawn in the same sprite
|
|
750
|
+
// layer as every live sprite, just grayscaled and non-interactive (see the
|
|
751
|
+
// .sprite.corpse CSS rule).
|
|
755
752
|
function renderCorpses() {
|
|
756
753
|
for (const id of Object.keys(corpseEls)) {
|
|
757
754
|
if (!corpses[id]) { corpseEls[id].remove(); delete corpseEls[id]; }
|
|
@@ -793,12 +790,12 @@ ${engineBundleJs ? `<script>\n${embedScriptText(engineBundleJs)}\n</script>` : `
|
|
|
793
790
|
return '<div class="hud-plan">plan: ' + text + ".</div>";
|
|
794
791
|
}
|
|
795
792
|
|
|
796
|
-
// The agent's own current world-knowledge-graph snapshot
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
//
|
|
800
|
-
//
|
|
801
|
-
//
|
|
793
|
+
// The agent's own current world-knowledge-graph snapshot — every OTHER live
|
|
794
|
+
// individual it believes it knows the position of, or "unseen" when it has no
|
|
795
|
+
// belief at all. Deliberately never ground truth: this is what the agent
|
|
796
|
+
// would actually ACT on, which a false pill or a told fact can make visibly
|
|
797
|
+
// wrong compared to where that individual really is — the gap IS the
|
|
798
|
+
// demonstration.
|
|
802
799
|
function beliefLineHtml(belief) {
|
|
803
800
|
const entries = Object.entries(belief || {});
|
|
804
801
|
if (!entries.length) return "";
|
|
@@ -1023,12 +1020,12 @@ ${engineBundleJs ? `<script>\n${embedScriptText(engineBundleJs)}\n</script>` : `
|
|
|
1023
1020
|
chatqEl.addEventListener("input", refreshPills);
|
|
1024
1021
|
refreshPills();
|
|
1025
1022
|
|
|
1026
|
-
// ---- deception pills
|
|
1027
|
-
//
|
|
1028
|
-
//
|
|
1029
|
-
//
|
|
1030
|
-
//
|
|
1031
|
-
//
|
|
1023
|
+
// ---- deception pills: a SEPARATE dynamic rail, alongside (never replacing)
|
|
1024
|
+
// the static one above. tmct.page.pillsForSpiderFly is the exact same pure
|
|
1025
|
+
// function spider-fly-turn.mjs exports — this page never reimplements the
|
|
1026
|
+
// true/false claim logic, only renders its output and fills #chatq on click,
|
|
1027
|
+
// same click-to-fill discipline as every other pill on this page (never
|
|
1028
|
+
// auto-submits).
|
|
1032
1029
|
function renderDynamicPills() {
|
|
1033
1030
|
if (!session || !Object.keys(lastAgents).length) { dynamicPillsEl.innerHTML = ""; return; }
|
|
1034
1031
|
const result = tmct.page.pillsForSpiderFly(lastAgents, selectedAddresseeId, {});
|