21 KiB
21 KiB
memory — JANKENBOTS
Durable memory for this project. Read at session start, update before session end. Date format: YYYY-MM-DD. Deep design detail lives in DESIGN.md (the full record carried over from the idea's plan.md); this file is the distilled decisions + live work.
Location: this project lives at
/mnt/f/jankenbots/jankenbots(WindowsF:\jankenbots\jankenbots) so the Unity Editor (Windows-only) and the git repo/docs share one folder.~/claude/projects/jankenbotsis a symlink to it. Work from either path. Name: the game is JANKENBOTS (working title was JANKENSTEIN; the archived idea folder keeps the old name at~/claude/archive/ideas/jankenstein/).
Decisions & rationale
- Concept (locked). ~25-player friendslop build-brawl: teams build a janky physics robot from themed scrap; each teammate pilots one functional part (pillar #6 — "you build your control scheme, not a robot"); death → free-roaming ragdoll gremlin. 8 design pillars in
DESIGN.md. - Engine: Unity (2026-07-10). Decided after a 3-angle netcode/prior-art study. The physics-party genre is overwhelmingly Unity (Fall Guys, Gang Beasts, Human Fall Flat, PEAK, Lethal Company, Party Animals, Stumble Guys, Trailmakers, Besiege, Robocraft); the two UE physics-heavy titles both swapped UE physics for Bullet. An earlier Unreal-MCP-tooling edge was correctly overridden. The defining risk is networked physics at ~25-player scale — no shipped game occupies that quadrant.
- Control feel v0.1 — driving = symmetric (2026-07-10). Each locomotion part = one pilot applying literal force ("you are the left tread") — the only model that generalises to arbitrary scrap contraptions and the one that keeps pillar #6. Tread pilot verbs: snap-to-cruise throttle (both slam forward = easy straight; coordination lives in the in-between), lock-pivot (called-play turns), passive lean (nobody idle). Asymmetric (throttle/steer split) held as the fallback if the prototype groans.
- Weapons = three-body call-and-response (2026-07-10). A weapon pilot perturbs the drivers' world → turn simultaneous chaos into rhythm: wind-up telegraphs a brace, a braced bonus makes drive+strike a combo, weapon doubles as engine/counterweight. Generalises to 5 archetypes — Punch / Grinder / Grip (later tier) / Guard / Passive. The weapon mix is a build-time chaos dial (over-building self-punishes = pillar #6 made mechanical).
- Team size & lobby math (2026-07-10). Team 3–5 (3 = smallest full driver+driver+weapon triangle; 5 = coordination/budget ceiling); lobby ≥2 teams; sweet spot 5 teams of 5. Unequal sizes balanced by a flat build budget (small team = concentrated & nimble; big team = distributed & tippy → equal power, different character), reinforced by physics (bigness = top-heavy, self-limiting) + coordination tax; matchmaking buckets pre-made friend groups & prefers equal sizes, NPC-fills the rest. No living "roamer" — everyone is in the bot; off-bot = gremlins (dead) only. Style vote needs ≥3 teams (2-team lobbies use fight-result + spectator vote).
- Prototype netcode = Unity NGO + Relay, host-authoritative (2026-07-10). Chosen for the throwaway first prototype (free, first-party, friends join by code, no port-forwarding). This does NOT commit the final architecture — server-authoritative state sync vs Photon Quantum deterministic lockstep is still deferred until the game is proven fun.
Open questions / TODOs
- ▶ M1 BUILD COMPLETE — only the 2-human playtest remains (see
docs/prototype-plan.md). Done so far (2026-07-10, all compiling clean + pushed): packages (NGO 2.13.0 +com.unity.services.multiplayer2.2.4 — the unified SDK that supersedes the deprecated standalone relay/lobby packages; pulls transport 6.5.0 + core/auth), 4 scripts inAssets/Scripts/{Net,Bot}/, sceneAssets/Scenes/M1_Arena.unity(NetworkManager+UnityTransport+NetworkBootstrap, ground/cam/light, set as build scene), replicated Player capsule prefab (Assets/Prefabs/Player.prefab, registered asNetworkConfig.PlayerPrefab).- ✅✅✅ SHOVE BALL + FOLLOW CAMERA BUILT & SMOKE-VERIFIED (2026-07-12) — M1 build is DONE. Wired both into
M1_Arenavia MCP, solo-host smoke test passed (ball spawns + rests on ground + shoves under force; camera moves to bot+offset and frames it). Committedb21f2d9. Shove ball = in-sceneNetworkObjectsphereShoveBall(1.5m, Rigidbody 10kg, linearDamping/angularDamping 0.5, Interpolate, Continuous) at world(0,0.75,6)(6m in front of the bot's +Z spawn facing, resting on the Plane at y=0);SphereCollider+Assets/Physics/ShoveBall.physicsMaterial(dyn/stat friction 0.4/0.5, bounce 0.3, Average combines);NetworkRigidbody+NetworkTransform→ host-authoritative, exactly mirroring the Bot. NO custom script (passive prop; host PhysX + NetworkRigidbody replicate it for free — correct M1-minimal call). Follow camera =Assets/Scripts/Camera/FollowCamera.cs(plain client-local MonoBehaviour, NOT networked) onMain Camera,target=Bot chassis,worldOffset (0,8,-12). Deliberately position-follow-only (fixed world offset + separately-slerped look-at, ignores the bot's roll/yaw) so the janky bot's spin/tip doesn't nauseate; escalation lever if it feels detached = follow bot YAW only. Auto-finds "Bot" by name iftargetempty. Control-scheme note confirmed this session: TreadPart v0.1 is forward + steer only, NO reverse (throttle W/↑ is forward-only per its own comment; turning = asymmetric throttle or lock-pivot; lean=anti-tip). Unity 6 (6000.5.3f1) API gotchas hit:PhysicMaterial→PhysicsMaterial,PhysicMaterialCombine→PhysicsMaterialCombine, Rigidbody.drag/.angularDrag→.linearDamping/.angularDamping(old names still readable but set the new ones).NetworkBootstrapis in the global namespace (noJankenbots.Prototype),HostGame()is asyncTask<string>. ▶ ONLY M1 STEP LEFT = the real 2-human friends playtest over Relay (this session's test was solo host + a scripted impulse as a ball-shove proxy). Then M2 = hammer. - ✅ BUILD + FORGEJO-RELEASE PROCESS ESTABLISHED (2026-07-12). Distribute playtest builds to friends as Forgejo release assets (Forgejo 11.0.15 at
git.rdx4.com, repo hashas_actions:true+ runners, but we do NOT use CI — the local-MCP-build path is far faster, no Unity-license-in-CI hassle). Process: (1) build via MCPmanage_build action=build target=windows64|linux64 output_path=F:/jankenbots/builds/<plat>/JANKENBOTS.exe|.x86_64→ returns ajob_id; pollmanage_build action=status job_id=…untilresult:succeeded(a ~empty M1 scene builds in ~65s, ~105MB uncompressed; the exe appears on disk BEFORE status flips to succeeded — wait for the status, don't trust file presence). Build scene =M1_Arena(the only enabled build scene); default platform is StandaloneWindows64. (2)zipis NOT installed in WSL → archive withpython3 -c "import shutil; shutil.make_archive('NAME','zip',root_dir='.',base_dir='FOLDER')"(win zip ≈40MB). Builds live inF:/jankenbots/builds(=/mnt/f/jankenbots/builds, OUTSIDE the repo — don't commit them). (3) Forgejo release via API with the token from~/.git-credentials(sed -E 's#https?://[^:]+:([^@]+)@.*#\1#', 40-char token, user megaproxy):POST /api/v1/repos/megaproxy/jankenbots/releases(JSON{tag_name,target_commitish=<sha>,name,body,prerelease:true}) → captureid; then upload each assetPOST /releases/{id}/assets?name=FILE.zip -F attachment=@path. Releasem1-playtest-2026-07-12(id 19) now carries Windows + macOS zips — https://git.rdx4.com/megaproxy/jankenbots/releases/tag/m1-playtest-2026-07-12 . Add more assets (e.g. Linux) to the SAME release id rather than making a new one. Installed build targets (checked 2026-07-12 viaBuildPipeline.IsBuildTargetSupported): Win64 ✅, OSX ✅, Linux64 ❌. Linux gotcha: needs Linux Build Support (Mono) installed in Unity Hub (Installs ▸ 6000.5.3f1 ▸ ⚙ Add modules) THEN an Editor restart — MCP can't install engine modules or restart the Editor; if absent,manage_build target=linux64errors "Platform 'StandaloneLinux64' is not installed." (User attempted the install 2026-07-12 but it hadn't registered even after a restart → build still ❌; Linux zip still owed to the release.) macOS gotcha: unsigned.app→ recipient must bypass Gatekeeper (right-click ▸ Open, orxattr -dr com.apple.quarantine JANKENBOTS.app); zipping from WSL over/mnt/f(mounts 777) preserves the Mach-O exec bit. Restarting the Editor DROPS MCP — reconnect via/mcpand re-set_active_instance(the hash is stable across restarts:jankenbots@47f7b88ac88d97d3). - ✅ CAPSULE REPLICATION VERIFIED (2026-07-11) — M1 netcode thesis proven. Two clients over Relay (host = original editor via MCP, client = ParrelSync clone), both capsules spawned + drove independently + replicated bidirectionally, smooth. The
input→ServerRpc→host-physics→NetworkTransformloop works over real Relay. ParrelSync 1.5.2 installed for local 2-client testing (clone at../jankenbots_clone_0, symlinks Assets+ProjectSettings; open it viaClonesManager.OpenProjector the ParrelSync menu; its MCP loses the port fight so only the original is MCP-controllable). - ✅✅ TWO-TREAD BOT DRIVES — M1 CORE THESIS VALIDATED (2026-07-11). Two clients over Relay, each piloting one tread of the shared bot; coordinating both to drive straight "feels good" (user's words). First attempt the bot was too hot + top-heavy and launched off on a nudge → tuned to stable: cruiseForce 450, linearDamping 1.5, angularDamping 6, maxAngularVelocity 3, centerOfMass (0,-0.6,0) (serialized override, implicitCom=false → persists). These are baked into the scene Bot. Gotchas found: (1) the step-2
PlayerPrefabcapsule still auto-spawns per client and PlayerDriver ALSO reads WASD → despawn capsules (or clear PlayerPrefab) for a clean bot test — in the real game players are seats, not free capsules; (2) each re-host mints a NEW Relay join code (old ones die) — stale codes were the cause of a failed join; (3) recompiling scripts mid-session forces the ParrelSync clone to recompile → don't Join during compile. Remaining M1: shove ball + follow camera (step 5-6), then the REAL verdict = a live 2-human friends playtest (the auto-drive was a solo proxy). - ✅ SHARED BOT BUILT (2026-07-11), solo-smoke-verified; awaiting 2-pilot drive test. In-scene
BotNetworkObject in M1_Arena: chassis Cube (Rigidbody 60kg + NetworkObject + NetworkTransform + NetworkRigidbody + SeatManager) with two child treadsTread_L/Tread_R(TreadPart, side Left/Right) at world ±1.2 X. In-scene bot auto-spawns on host; seat claim + gating verified solo. DESIGN FIX (important): the two drafts were mis-wired — TreadPart gated on NetworkObjectIsOwner(needs per-tread ownership → impossible, NGO forbids nested NetworkObjects in a spawned prefab) while SeatManager'sOwnsSeat/PilotOfAPI sat unused. Rewrote TreadPart to seat-based gating: both treads share the chassis NetworkObject; a client drives the tread whose seat it holds (PilotOf(side)==LocalClientId), host re-validatesOwnsSeaton the RequireOwnership=false RPC. Also swapped TreadPart toKeyboard.current(New-only input). Controls: W/↑ throttle · Shift pivot · A/D lean. Moved SeatManager OnGUI below the bootstrap panel (was overlapping). - ✅ UGS GATE CLEARED + HOST PATH VERIFIED (2026-07-10). Cloud project jankenbots (
cloudProjectId a0d222ae-c79b-4120-bc0d-947bfd7600cb, orgmegaproxy) is linked (has been in ProjectSettings since project creation) AND Relay is now activated in the dashboard (the missing step — done via cloud.unity.com ▸ Development ▸ Products ▸ Relay; there is NO enable toggle, opening the product page activates it). Verified by an in-editor Play-mode smoke test:UnityServices.State=Initialized, anonymous auth signed in,HostGame()created a real Relay allocation + join code, host's Player capsule auto-spawned (IsSpawned, owner=0). The host half of M1-step-2 works end-to-end. Still unverified: a remote client joining + peer-to-peer replication (needs a 2nd instance — standalone build viamanage_buildor a ParrelSync clone). - Next build steps: (5) shared bot = chassis Rigidbody + 2
TreadParttreads +SeatManager(⚠TreadPartstill reads legacyInput.GetAxis— swap toKeyboard.currentlike PlayerDriver was, project is Input-System-New-only); (6) shove ball + follow cam; (7) 2-friends feel test over Relay (needs a standalone build viamanage_buildor a ParrelSync clone for the 2nd client). - Verified Relay API gotcha (baked into NetworkBootstrap): with the unified SDK,
new RelayServerData(allocation, "dtls")does NOT exist — useAllocationUtils.ToRelayServerData(allocation, "dtls")(AllocationUtilsis inUnity.Services.Relay.Models). Corrected via live editor reflection.
- ✅✅✅ SHOVE BALL + FOLLOW CAMERA BUILT & SMOKE-VERIFIED (2026-07-12) — M1 build is DONE. Wired both into
- Project location decided + unified —
F:\jankenbots\jankenbots(git + Unity + docs together), symlinked~/claude/projects/jankenbots. Unity.gitignore/.gitattributesin place. - Unity project created — fresh URP + Input System template (
Assets/,SampleScene,InputSystem_Actions). Still to add: NGO + Relay + Lobby packages (part of M1 above). - Unity MCP working — CoplayDev server on
127.0.0.1:8067, portproxy8068→8067,.mcp.json→172.27.208.1:8068/mcp; handshake verified (v3.4.4). Tools only load when Claude is started from this project folder with Unity open + server running. - Netcode architecture (deferred, the real risk) — dedicated server-authoritative state sync (Robocraft 2 blueprint) vs Photon Quantum lockstep (Stumble Guys precedent). Decide after the fun is proven + the 25-player physics spike. Netcode target ≈ 25–30 primary rigid bodies + gremlins/debris.
- The 25-player physics/netcode spike — two ~30-joint bots colliding at arena scale, ≥100 ms latency, min-spec. The make-or-break gate before scaling up.
- Remaining design questions (detail in
DESIGN.md): build-coupling tightness, hidden per-player agenda, at-scale voting, part taxonomy, scavenge-contest rules, art style, progression (cosmetic-only), final name (working title JANKENSTEIN; alts BODGEBOTS / SCRAPYARD SCRUM / CLANKERS / RUSTBUCKETS / JALOPY WARS).
Session log
2026-07-12 (session 4 — M1 build finished: shove ball + follow camera)
- ▶ RESUME HERE next session: the entire M1 build is done (bot drives, shove ball, follow camera — all in
M1_Arena, all smoke-verified). The ONE thing left in M1 is the real 2-human friends playtest over Relay — flip off anydebugAutoDriveFull, don't rely on scripted proxies, get two actual people each on one tread pushing the ball around. That playtest is the true fun verdict. After it → M2 = add a hammer (first weapon). See the "SHOVE BALL + FOLLOW CAMERA" ✅✅✅ block above for every value/gotcha. - Fanned out two Sonnet subagents (camera-script author + ball-networking designer) while MCP was down, then wired both into the scene via MCP once the editor came back. Ball needs no script; camera is
FollowCamera.cs. Confirmed the control scheme is forward + steer, no reverse. 2 commits pushed (87f929bcamera script,b21f2d9scene+ball+material). Unity-6 physics API renames noted in the block above.
2026-07-11 (session 3 — M1 bot drives, thesis validated)
- ▶ RESUME HERE next session: M1 core is proven (two-tread bot drives over Relay, feels good). Remaining M1: (1) build the shove ball (big physics sphere) + a follow camera framing the bot — makes coordination purposeful; (2) run the real 2-human friends playtest (this session used a host-side
debugAutoDriveFullauto-drive as a solo proxy — flip it off / don't rely on it with real players); then M2 = add a hammer. To bot-test cleanly: despawn the player capsules or clearNetworkConfig.PlayerPrefab(they double-drive on WASD), and remember each re-host = a NEW Relay code. - Built the whole M1 bot this session via MCP + ParrelSync 2-client testing; tuned physics live after it launched off; validated it drives straight with two pilots. All committed + pushed (see the M1-progress TODO block above for the full state, gotchas, and verified API/tuning values). ParrelSync clone editor can be closed between sessions; reopen via ClonesManager when needed.
2026-07-10 (session 2 — M1 build start)
- Started Milestone 1 via a research/draft workflow + serial in-editor build. Ran a 9-agent workflow (verified NGO/Relay API research → adversarial verify → draft 4 scripts → integration plan); the verify agent installed the packages to reflect against the live editor, catching two hallucinated Relay APIs before any code hit the project. Then serially, all main-loop MCP work (packages/scene/prefabs are stateful/single-editor → NOT parallelized): dropped scripts (compile clean, 0 errors), built
M1_Arenascene + NetworkManager, made the replicated Player capsule prefab, fixed PlayerDriver input for New-only Input System. 4 commits pushed. Stopped at the UGS-link gate (see TODO) — nothing is runtime-testable until that's linked. - Runtime host smoke-test (solo, no 2nd client): enter Play via
manage_editor play, thenexecute_codeto callnb.HostGame()and pollread_console— saw QosJob region pings +Hosting with join code XXXXXX. Note: theeditor/stateresource's background tick FREEZES (goes stale) during playmode transitions, but directexecute_code/read_consolecommands still work — probe with those, don't trust the stale state snapshot. - MCP resource URI correction: editor state is
mcpforunity://editor/state(not/editor_state); project infomcpforunity://project/info.find_gameobjectswildcard*returns nothing — search by name/component/path.execute_codeuses CodeDom (C# 6) by default → fully-qualifyUnityEngine.Object, no C#12 syntax.
2026-07-10 (session 1 — promotion + setup)
- Promoted from
ideas/jankensteinto a real project. Scaffolded the WSL-side project home (this repo): filledCLAUDE.md, seeded thismemory.mdfrom the idea'splan.md, carried the full design record over asDESIGN.md, addeddocs/prototype-plan.md. Idea folder archived toarchive/ideas/jankenstein. - Decided to build a basic networked prototype first (user wants to test the coordination feel with real friends — local split-screen won't capture the social/voice-chat core). Stack: Unity NGO + Relay, host-authoritative, throwaway netcode. Milestone 1 = one shared bot, each player one tread.
- Consolidated the project + seeded Unity MCP config (
.mcp.json→unityHTTP server at172.27.208.1:8080/mcp,.claude/settings.local.json,docs/mcp-setup.mdrunbook), Unity.gitignore/.gitattributes(no LFS yet). - Renamed JANKENSTEIN → JANKENBOTS and unified folders. User created the Unity project at
F:\jankenbots\jankenbots(named it jankenbots). Moved the seeded repo (git history + docs +.mcp.json) into the Unity project root so it's one folder; renamed the Forgejo repojankenstein → jankenbots+ updated the remote; re-pointed the symlink to~/claude/projects/jankenbots. Unity project is a fresh URP/Input-System template (hasAssets/,SampleScene,InputSystem_Actions). MCP status: ✅ WORKING (verified 2026-07-10, mcp-for-unity-server v3.4.4). Server binds127.0.0.1:8067(HTTP mode), bridged to WSL vianetsh portproxy 0.0.0.0:8068→127.0.0.1:8067; Claude reacheshttp://172.27.208.1:8068/mcp(.mcp.json). Key gotcha: 8080 is unusable — it's in a Hyper-V/WinNAT reserved range (WSL2), bind fails with WSAEACCES/Errno 13; use a non-reserved port + a distinct proxy port. Full detail indocs/mcp-setup.md. Session wrapped here — everything committed & pushed; resume by opening a fresh Claude session from this folder (Unity open, MCP server running) and starting Milestone 1.
External references
- Full design record:
DESIGN.md(this repo) — control feel v0.1, weapon archetypes, lobby math, tech direction, netcode prior art. - Prototype build-plan:
docs/prototype-plan.md. - Wiki (orientation): http://192.168.1.249:6876/projects/jankenbots
- Idea-phase history:
~/claude/archive/ideas/jankenstein/(original brainstormplan.md+ session logs). - Netcode prior art (Rocket League GDC talk, Fall Guys/Robocraft/Stumble Guys case studies, Gaffer On Games) — cited in
DESIGN.md→ References. - Unity MCP setup runbook:
docs/mcp-setup.md. Server = CoplayDev/unity-mcp in HTTP mode host-side; Claude (WSL) connects athttp://172.27.208.1:8080/mcp(.mcp.jsoncommitted). Bridge pattern mirrors the UE servers (host-side HTTP + host-IP). Not yet stood up — needs the editor + package installed.