Records: - BuildDrawer 2-pass iteration + UI-tray feedback lesson - Phase 17/18 closure sprint (StockpilePanel + DaySummary + atmospheric audio) - Phase 19 sprint (hint tour + Help modal + tooltip pass, decision: hint approach) - Two new recorded patterns (tray UI rule, generic ui_panel_opened signal) - Drag-paint bug logged for Phase 20 polish - Contracts-first pattern proven 7th + 8th time Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 KiB
memory — rimlike
Durable memory for this project. Read at session start, update before session end. Date format: YYYY-MM-DD.
A 2D, tile-based cute-farming-RPG-meets-colony-sim — Rimworld DNA, Going Medieval × Stardew lodestars — shaped for mobile and handheld. Promoted from ~/claude/ideas/rimlike on 2026-05-10 after a single deep brainstorm session. Realistic MVP timeline: 3–6 months solo.
How to read this project
memory.md is the index of decisions and open questions. The deep specs live alongside in docs/:
| File | Contents |
|---|---|
docs/design.md |
Game design — core loop, simplifications, skills, statuses, mood, weather, stockpiles, production, combat, death/burial, storyteller corpus |
docs/architecture.md |
Tech — pawn AI / job system, time/tick model, Godot 4 engine layout, TileMap split, all subsystems (mood, lighting, rooms, hauling, production, combat, storyteller) |
docs/ui.md |
Touch UX — work-priority matrix, stockpile/container screens, mood/lighting/rooms cues, combat banners, storyteller event UI, screens still to design |
docs/art.md |
Owned assets (ElvGames bundle primary, Ventilatore secondary), license, autotile gotcha, audit list, candidates kept for record |
docs/implementation.md |
Phased build plan — 21 phases (audit → P0 scaffold → … → P20 export). Checklists, acceptance demos, scope-cut levers, de-risking spikes. Track progress here. |
When working on a feature, read memory.md first, then the relevant docs/ file(s). For "what do I build next?" check the Status row at the top of docs/implementation.md.
Decisions & rationale
Distilled from the brainstorm. Each lock has a "why" — change with deliberate intent.
Pillars
| Decision | Choice | Why |
|---|---|---|
| View | Top-down grid for gameplay (pathfinding, designation, floor) + 3/4-perspective rendering for vertical structures (walls, doors, furniture). | Re-decided 2026-05-10 after exhausting the asset library: every wall pack we own is RPG-style perspective (Stardew / Going Medieval style), not Rimworld-style top-down. Pivoting the renderer (Y-sorted entity sprites for walls) makes the entire library usable as-is and replaces the "we need to author or commission" bottleneck. Gameplay grid + pathfinding stay identical; only the rendering of vertical structures shifts. |
| Wall layer rendering | Walls are entity sprites (Sprite2D / Y-sorted Node2D), not TileMap cells. Wall TileMap layer (Layer 2) becomes data-only — used for pathfinding-impassable + room-detection BFS, but doesn't render. |
Same source as the view-style pivot above. Consequence: doors, crates, furniture all live as entities with Y-sort; floor and designation-paint still tile-based. Architecture.md TileMap-layer section needs an annotation. |
| Primary platforms | iOS + Android touch, then Steam Deck / ROG Ally gamepad. Desktop falls out for free. | Mobile is the hard constraint; Deck inherits. |
| Ambition | itch.io + TestFlight release. Real artifact, small audience. | Drives engine choice; no app-store polish-tax. |
| Engine | Godot 4 (GDScript) | 2D-first, free, exports everywhere we need, fast iteration. |
| Tile size / style | 16×16 pixel art, cute-farming-RPG primary (ElvGames bundle), Ventilatore as medieval accent | ElvGames "Ultimate Farming RPG" Humble bundle owned (~2.8 GB, 70+ packs). Tone: Stardew × Going Medieval × Rimworld. |
| Setting | Medieval fantasy with cute palette | Owned-art alignment + clearer scope (no electricity / hydroponics / energy weapons) + underexplored on mobile. |
| Run shape | Open-ended sandbox, autosave, persistent world | Player picks up where they left off. |
| Session length | 5–15 min target | Drives every UI and pacing choice. |
| Default speed | Fast (5×), with auto-pause on event | 1 in-game day ≈ 5 min real time. Solves the "watch a pawn walk for 60s" problem; 1× exists for combat / fine work. |
| Goal scaffolding | Light storyteller prompts | Soft, dismissible nudges give each short session shape without forcing scenarios. |
| Combat | Realtime with auto-pause on threat | Rimworld-feel; touch-friendly. |
| Health | Single HP per pawn + status effects (Bleeding/Sick/Tired/Hungry/Wet/Cold/Downed/...) | ~80% of the drama for ~5% of Rimworld's health-system code. |
| Scale | 3–6 pawns, 80×80 MVP map (architecture sized to ~120² ceiling) | Roughly Stardew-farm size; readable when zoomed in, doesn't fit a phone screen — forces the world-view camera (pinch / pan / jump-to-alert) rather than strategic-overview-on-phone. |
| Priority levels | 5 (Critical / High / Normal / When idle / Off) | Matches Rimworld + Going Medieval contract. |
| Failure state | Ghost colony — no game over; storyteller drops wanderer in 3–5 days | Mobile-friendly; preserves player investment. |
| Engine version | Godot 4.6.2 stable (Win64 binary at D:\godot\Godot_v4.6.2-stable_win64.exe) |
Locked for reproducibility; pinned in project.godot features. |
| Renderer | GL Compatibility (mobile + desktop), not Forward+ | Max device reach; Forward+ would lock out older phones. |
| Repo location | Physical: /mnt/d/godot/rimlike/ (D: drive, fast for Windows-side editor). Symlink: ~/claude/projects/rimlike → physical. |
Mirrors tavernkeep's pattern. Both WSL and Windows access without crossing the WSL net bridge. |
| Player walls | Wood + stone via Pixel Crawler Walls.png (entity sprites, Y-sorted; no autotile in Phase 5). Single-sprite-per-material is the Phase 5 ship; per-direction variants are a polish item. |
After the rendering pivot to 3/4 perspective, the Pixel Crawler Walls.png pack becomes directly usable. It has 4 wood materials + a sandstone variant with clear corner/edge pieces. Phase 5 ships with one sprite per material (uniform-looking walls); Phase 17 can add per-direction variants if playtest reveals the visuals feel flat. Stardew-cabin warmth restored without authoring or commission. |
Architecture (tech)
- Sim tick 20 Hz, render 60 Hz, decoupled. Pawn positions lerp between sim ticks. (
docs/architecture.mdTime / tick model) - Pawn AI: 5-layer pipeline (Decision → WorkProvider → Job + JobRunner → Status interrupts → Player overrides). Slimmer than Rimworld's ThinkTree. ~800–1500 LOC GDScript for full MVP.
- TileMap layers: 0 Terrain · 1 Floor · 2 Wall · 3 Designation · 4 Roof · 5 Fog. Furniture / Pawn / Item / EffectFX as scene-instanced entities (not TileMap).
- Pathfinding:
AStarGrid2D(built-in), updated on wall/door/furniture changes. - No background simulation — app backgrounded = sim paused. Avoids "lost colony to a raid while at work."
- Save format: between sim ticks only; JobRunner mid-toil state round-trips from day one.
Game design
- 5 skills (Manual Labor / Crafting / Cooking / Medicine / Combat), 0–10 each, level by use, multiplicative speed/quality bonus. Skills modify duration and quality, never permission.
- 9 work categories (Construction / Mining / Hauling / Cleaning / Crafting / Cooking / Plant / Doctor / Combat). 5-level priority matrix per pawn.
- Storage: floor zones AND independent crate furniture (4 stacks each), unified by
StorageDestinationinterface. 16 filter chips (Wd/St/Ir/Cu/Ag/Au/Cl/Veg/Mt/Gr/Ck/Md/Tl/Wp/Ar/Co), 5 priorities with Rimworld flow semantics. One stack per tile, one type per tile. - Production: 2-step where medieval-sense (Iron→Ingot→Weapon, Grain→Flour→Bread); 1-step otherwise. 5 workbenches (Carpenter, Smelter, Smithy, Cooking hearth, Millstone), ~22 recipes. Full Rimworld bill semantics (one-shot count / forever / until-N + ingredient-quality filter + skill threshold).
- Quality system (Shoddy/Normal/Excellent/Masterwork/Legendary) on every crafted item; multiplicative stat bonus. Quality from crafter skill + RNG only (inputs are just resources).
- Mood: ~13 thoughts (data-driven registry, mix persistent + event-driven). Soft breaks at sustained mood < 25 for 30 in-game min — Sulking or Wandering, recover at mood ≥ 35.
- Lighting (real shader at night), auto-detected rooms (named by furniture, scored for beauty + dirtiness), dirtiness + Cleaning (8th work category), beauty score with Quality multiplier.
- Roofing: indoor = Layer-4 Roof flag, sim-data only (no rendering, just an indoor tint on floors). Auto-roof when walls enclose ≤8 cells (BFS); No-Roof designation for courtyards. Plants don't grow indoors.
- Weather: 4 types (Clear / Rain / Storm / Cold snap), daily roll, season-weighted. Wet status accumulates outside in rain, decays indoors. 4 seasons × 12 days = 48-day year.
- Combat: 3 weapons (sword/axe/bow), 3 armor slots (helm/cuirass/boots). Walls + trees provide cover. Two-roll resolution (hit, then damage with armor reduction). Downed-then-rescue death model; doctors auto-prioritize. Combat=Off "defends if cornered, won't volunteer." Friendly fire ON.
- Death / corpses: Both burial AND cremation. Graveyard = special stockpile (Corpses-only); pawns dig graves, place permanent grave markers (tap → deceased pawn-detail). Cremation pyre = furniture with single recipe (1 corpse + 5 wood). Corpses decay 0–50 fresh / 50–100 rotting (no butcher) / 100 rotted.
- Storyteller: 25 prompts written in
docs/design.md. Daily 6am roll, weighted pool, per-category cooldowns, tension model alternates quiet/threat per Tynan Sylvester pacing. Ambient banner for low-stakes, modal auto-pause for choice events.
Touch UX
- Bottom-sheet menus instead of right-side panels. Long-press = inspect/context. Tap world = select. Speed/pause buttons fixed top.
- Work-priority matrix: 9 columns × N pawns, sticky pawn-name column, horizontal scroll on phone. Tap-to-cycle priority, long-press for 5-chip picker, swipe column for bulk-set. Per-pawn and per-job views layered on top.
- Stockpile/container UI: 4×4 chip grid for the 16 filter categories; same UI for floor zones and crates.
- Storyteller events: ambient banners for nudges/seasonal/lore; modal auto-pause for wanderer/threat/disease/milestone. Events log + "while you were away" digest at resume.
- Indoor tint marks "this is inside" without needing roof rendering — matches Stardew/Rimworld convention.
- World-view camera: pinch-zoom + drag-pan + double-tap-to-center; selected pawn does not force-follow. Storyteller alerts/banners include a Go there tap that pans the camera to the event tile. No minimap in MVP — revisit if playtest shows people getting lost on the 80² map.
Art strategy
- ElvGames "Ultimate Farming RPG" Humble bundle is the primary art (
/mnt/d/godot/assets/humble set new/, ~2.8 GB, 70+ packs, all 16×16, ElvGames license: commercial OK with credit). - Ventilatore Fantasy Tileset Complete Bundle stays as medieval accent for biome variety / decorative props / animated water.
- Mana Seed series considered but dropped from buy plan (the bundle covers what we'd planned).
- Authoring still required: designation overlays (~2 hrs custom), possibly autotile bits on bundle wall sheets, possibly wolf sprite, possibly grave marker.
Known bugs / triage backlog
Reported from playtest. Triaged but not yet fixed. Plan: knock out as a bug-triage patch out-of-phase before Phase 18 (Audio) — same shape as the 2026-05-12 PC-controls patch.
- [HIGH] Torches don't build when placed. Reported 2026-05-15, fixed 2026-05-15. Root cause: Torch/Bed/Crate/Workbench/CremationPyre didn't call
World.register_build_site(self)in_ready(only Wall/Floor/Door/GraveSlot did). ConstructionProvider iteratesWorld.build_queueso the unregistered entities were never offered as jobs. The seeded cabin pre-built everything via_spawn_complete_*helpers, masking the gap until a player painted a fresh furniture designation. Fix: added register_build_site / unregister_build_site to all five entity types. - [HIGH] Two of three pawns sit idle, one does all work. Reported 2026-05-15, fixed 2026-05-15. Root cause: pawns get stranded on tiles that became impassable mid-walk. Sequence: pawn-A walks a path computed pre-wall; pawn-B builds a wall on a tile in pawn-A's path; pawn-A keeps stepping along the now-stale path and lands on the wall tile; pathfinder requires a walkable START, so all subsequent find_path calls from pawn-A return empty → pawn-A is idle forever. The Phase 6 wall-trap-bug fix only protected the BUILDING pawn (adjacent-stand); bystanders + walk-through cases weren't covered. Two-part fix: (a) Wall._complete dislodges any pawn standing on the tile via new
Pathfinder.find_nearest_walkableBFS helper; (b) Pawn._advance_walk re-checksnext_tilewalkability before snappingtile, aborts walk + cancels job + lets Decision reroute. Defense in depth. - [MED] Pawns render behind floor tiles. Reported 2026-05-15, fixed 2026-05-15. Root cause: Floor entity anchored origin at tile-center (
tile.y*16+8), same Y as Pawn — Y-sort tiebreak fell to scene-tree order, Floor (spawned later) drew over Pawn. Fix: moved Floor origin to top-of-tile (tile.y*16) so Floor.y < Pawn.y under Y-sort; _draw offsets compensate (rect spans y=0..TILE_SIZE_PX instead of -half..+half).
Older bugs noted in passing but never fixed:
- [LOW] Bed-claim failure for 2/3 pawns when beds are free (logged 2026-05-11).
Bram bed claim failed at /root/Main/World/Bed — sleeping on flooreven when beds free. Doesn't gate progress; needs sleep-system audit. - [LOW] Save mid-INTERACT/mid-BUILD restarts toil from 0 on load (Phase 16 known acceptable gap). Walk toil round-trips; multi-step interact does not. Tolerable per Phase 20 tuning note.
- [MED] Drag-paint eaten by camera with paint tool active (logged 2026-05-16). When a Designate/Build/Stockpile tool is active in BuildDrawer, the player should be able to click-and-drag to paint a rectangle of cells. Instead, camera_rig's drag-pan consumes the InputEventScreenDrag / MouseMotion and the paint stays single-cell. Contradicts the 2026-05-11 note that claimed drag-paint worked — that was selection drag-painting via Designation, not the camera-vs-paint priority case. Fix needs Selection or Designation to set
set_input_as_handled()on drag events when a paint tool is active, or camera to skip pan whenDesignation.active_tool != TOOL_NONE.
Open questions / TODOs
Audit / unblock-the-prototype action items
Total ~75 min. 3 of 5 closed on 2026-05-10; see session log + docs/art.md for findings. Two open.
- Aesthetic harmony test — needs your eye. ElvGames Forest tile vs Ventilatore tile, side-by-side. Decides whether Ventilatore stays as accent or gets shelved. ~15 min.
- ElvGames autotile audit — done.
FG_Fortress.pngIS autotile-solvable (tan stone, ~20–30 modular pieces);FG_Houses.pngis NOT (pre-built decorative house compositions, not modular wall variants). Iconic Homestead $19.99 fallback not needed. New decision required — see Open questions below. - Wolf sprite source — done. No wolf in the bundle anywhere. Need a custom commission, a CC0 sprite, or a Ventilatore find. New decision required — see Open questions below.
- Grave marker source — done.
Retro Graveyard 16x16 Tileset [Kingdom Explorer]confirmed in Tier 3, full graveyard suite. Direct use, no custom work. - License compilation — maintain credits string for every pack used (ElvGames + Ventilatore + Kingdom Explorer + any others). Display in game's credits screen. Confirm specific terms per pack before any commercial release.
Design topics still open
Resolved: wall material strategy. Lock = custom-author wood + stone walls (option b). Player builds wood-cabin walls from day one (corner/T/cap variants authored on top of FG_Houses.png wood-and-blue-roof material, ~½ day work) then upgrades to stone fortress walls later (FG_Fortress.png autotile-solvable as-is, ~few hours). Phase 5 slips ~3 days but the Stardew-cabin-warmth aesthetic survives, which was the original anchor. See docs/art.md Wall-material decision.
- Wolf sprite acquisition (NEW from 2026-05-10 audit): bundle has nothing canine-predator; Ventilatore checked 2026-05-10, also nothing (Ventilatore is character + terrain + decoration; no animal/creature sprites at all besides player + slimes). Remaining options: (a) commission a 16×16 wolf (idle + 2–4-frame walk × 4 directions; ~$30–60 paid commission); (b) source a CC0 wolf from OpenGameArt; (c) reskin a bundle animal placeholder for MVP (e.g. recolor a dog from
Animal Sprites Pixelart) and replace later. Phase 10 blocker — can defer until then; placeholder from option (c) unblocks the combat/AI work meanwhile. - Auto-roof big-room UX: the ≤8-cell BFS cap silently fails on rooms larger than 8×8. Decide whether to (a) keep the cap and surface "this area is too large to roof — split with an interior wall" hint when the player encloses one, (b) bump the cap to ~16 with the same hint at the new threshold, or (c) detect any enclosed area regardless of size. Affects
EnclosureDetector+ a new room-feedback UI. - Onboarding / first 60 seconds: mobile-specific. Don't copy Rimworld's tutorial.
- Touch UI for non-priority screens: world view, build drawer, alerts, day-summary, pawn detail. See
docs/ui.md"Screens still to design." - Background time / "while you were away" mechanic — locked to no background simulation in MVP; revisit if it feels bad in playtest.
- Audio direction — who/where for SFX + ambient track? Bundle has 11 music + 8 SFX packs covering most needs.
- Steam Deck input parity — gamepad-driven cursor, or full menu navigation by D-pad? Probably both.
- Localization stance — English-only for MVP, but architect strings for i18n (already locked in CLAUDE.md).
- Pawn name/backstory generation — hand-curated list vs simple generator.
- Naming the game — "rimlike" is a working title.
- Monetization stance — free? PWYW? Premium?
- Tech / research progression — medieval tech tree shape.
- Map / world generation — fixed seed for slice; procgen later.
Tunable in prototype (not real "open Qs", just numbers to playtest)
- Sleep mood gradient values (
+5/+0/−2/−5/−8) - Wet status thresholds (25 / 60) and accumulation rates
- Season weather weights (Spring/Summer/Autumn/Winter distributions)
- Hit-chance bonuses (skill ×5%, range ×5%, cover 40/20%)
- Bleed-out timer (6 in-game hours)
- Various mood thought magnitudes and decay times
Vertical slice (MVP target)
Same scope as locked in ~/claude/ideas/rimlike/plan.md. Realistic timeline 3–6 months solo for an MVP this rich.
- 1 biome (temperate forest, ElvGames Forest Tileset 4 Seasons; Ventilatore foliage accents).
- 1 map, 80×80 tiles, fixed seed for now.
- 3 starting pawns ("settlers" / "villagers"), each with name + portrait + one-sentence backstory.
- Verbs: chop wood, mine stone & ore, build walls/floors/furniture/crates, plant/harvest crops (3–4 types), cook meals (recipes), haul, repair, clean.
- Needs: hunger, sleep, mood (~13 distinct thoughts, soft breaks at sustained mood < 25).
- Status effects: Hungry, Tired, Bleeding, Sick, Downed, Wet (Damp/Soaked), Cold.
- Storage: floor zones AND containers, 16 filter chips, 5 priorities.
- Quality system on all crafted items.
- Lighting — torches + hearths emit light; visual darkness at night.
- Rooms — auto-detected, named by contents, beauty + dirtiness scored.
- Cleaning as 8th work category.
- Day/night cycle, ~5 min per day at default speed. Seasons (Spring/Summer/Autumn/Winter, 12 days each).
- Weather: Clear / Rain / Storm / Cold snap.
- One disaster type: wolves at night (bandit raids deferred).
- One storyteller: random quiet/threat alternation, 25 prompt corpus.
- Save/load, autosave on suspend, single slot.
- Touch UI end-to-end (no desktop-only gestures).
- Sound: minimal — UI clicks, ambient day/night loop, alert sting.
Session log
2026-05-10
- Promoted from
~/claude/ideas/rimlike/(single multi-hour brainstorm session). - Scaffolded
projects/rimlike/from_templates/project/. CustomizedCLAUDE.md. Distilledplan.mdinto thismemory.md. Moved companion files (design / architecture / ui / art) intodocs/.git init, first commit "Initial scaffold". Created Forgejo reporimlike(private), set HTTPS remote, pushedmain. Archived idea folder to~/claude/archive/ideas/rimlike/. - Wired Godot MCP Pro:
.mcp.json,.claude/settings.local.jsonallowlist, three project-local subagents (quick-edit,researcher,gdscript-refactor). Added the MCP-Pro and tiered-delegation sections toCLAUDE.md. Editor plugin /addons/godot_mcp/re-copy still pending Godot project scaffold. - Reviewed
docs/againstmemory.mdandCLAUDE.md. Decisions made:- Map size bumped from 40² → 80² for the MVP slice; architecture sized to ~120² ceiling. Pawn count stays at 3 start / 6 cap (frontier feel was rejected in favor of "split-the-difference" sizing — Stardew-farm scale, not Going-Medieval scale).
- World-view camera = pinch-zoom + drag-pan + double-tap-to-center; storyteller alerts include a Go there tap. No minimap in MVP. No follow-cam (avoids fighting the player when issuing build orders across the map).
- Storyteller cooldown semantics: per-event AND per-category, both gates must pass (resolves the design.md vs architecture.md disagreement).
MAX_STACKS_PER_THOUGHT = 5(was named-but-unset).- Hauling-loop fallback: items that fail to find any valid destination after 3 retry passes drop on the floor and surface as a passive "No stockpile accepts X" alert.
- Cleaned up doc rot in
docs/design.mdanddocs/architecture.md— both had stale "8 work categories" intermediate sections still next to the canonical "9" lists. Removed the (8) snapshots. - Updated
docs/architecture.mdperf assumptions (60² → 80² with 120² ceiling). docs/ui.mdgot a new World view camera (locked) section; removed the world-view bullet from "Screens still to design".- Open: auto-roof big-room UX (added to TODOs above) — the ≤8-cell BFS cap silently fails on bigger rooms; player feedback path needs a decision before EnclosureDetector lands.
- Wrote
docs/implementation.md— 21-phase build plan with checkboxes, acceptance demos, scope-cut levers, and de-risking spikes. Status row at the top of that file is the canonical "where are we now" pointer. - Project location moved from
/home/megaproxy/claude/projects/rimlike/to/mnt/d/godot/rimlike/(D: drive). Symlink at the original WSL path preserves the home-CLAUDE.md layout convention. Setgit config core.filemode falseto silence DrvFs's everything-is-0777 false-positive. Mirrors tavernkeep's pattern; both WSL and Windows access without crossing the WSL net bridge. - Phase 0 scaffold landed.
project.godot+ 7 autoloads + smoke-test scene + addons re-copy + folder layout. Used GL Compatibility renderer (not Forward+) for max mobile reach. Folder layout matches tavernkeep (autoload/at root, scripts co-located inscenes/) — not thescripts/autoloads/mirror layout originally sketched inimplementation.md. Headless verification:godot --headless --path . --quitexits 0 with the smoke-test message. Editor-side green-dot check pending — needs you to open the editor once. - Asset audit ran via researcher subagent (Haiku). 3 of 5 items closed. Findings:
FG_Fortress.pngautotile-solvable (tan stone).FG_Houses.pngNOT autotile-solvable (pre-built decorative compositions). Iconic Homestead fallback not needed. Opens a new wall-material decision (see Open questions).- No wolf sprite anywhere in the bundle. Opens a wolf-acquisition decision (see Open questions).
Retro Graveyard 16x16 Tileset [Kingdom Explorer]confirmed in Tier 3 — full graveyard suite, ready for direct use in Phase 14.
2026-05-11
-
Phases 1–11 all shipped between 2026-05-10 and 2026-05-11 (the in-context session log lagged behind the commits). See
docs/implementation.mdStatus table for canonical phase-by-phase state; below is just the headline. -
Phase 9 (Status + Medicine) + Phase 10 (Combat + Wolves) shipped as the "drama pair" via 3-agent fan-out (Agent A: HP/Status on pawn, Agent B: DoctorProvider + medical bed + Rescue/Treat toils, Agent C: Wolf entity + WolfSpawner). Opus integrated into
scenes/world/world.tscn+world.gd(middle bed at (47,24) markedis_medical=true). -
MCP runtime verified both phases. Phase 9: injected 75 dmg + Bleeding(2) into Bram → went Downed (hp 25) → Edda+Cora both volunteered
doctor → 'Rescue Bram → bed at (47, 24)'→ treated → Bram healed to 94.2 hp, statuses cleared, returned to work. Phase 10:[wolf] RAID: 1 wolf(ves) spawned at [(53, 2)]fired at day 3 22:00 (darkness ≥ 0.8); 4 wolves alive across raid cycles by day 4 01:51. Screenshot confirms medical-bed red-cross marker and wolf silhouettes at night. -
Phase 10 deliberately partial — wolf-side combat (two-roll, bleed on hit) shipped, but pawn-side weapons/armor/cover/friendly-fire deferred. Acceptance demo's full chain (wolf → bites → pawn bleeds → doctor saves) awaits player weapons. WolfSpawner pack size 1–2 vs design target 1–4 — tune up post Phase 20 numbers pass.
-
Bleed-out timer shipped at demo value
BLEED_OUT_TICKS = 1200(~ minutes) instead of design value432000(6 in-game hours). Documented instatus_catalog.gd; flip on first time-balance pass. Recorded so it doesn't ship to a release at the demo value. -
Bed-claim bug noticed in passing during ULTRA-speed run:
Bram bed claim failed at /root/Main/World/Bed — sleeping on floorfor two of three pawns even when beds free. Doesn't gate Phase 12; logged for separate triage. -
Phase 12 (Seasons + Weather) shipped same day. Three-agent fan-out (Agent A = clock seasons + season top-bar + terrain palette; Agent B = Weather autoload + procedural rain overlay + storm flash; Agent C = Wet/Cold statuses + mood thoughts + shelter check). Opus prepped contracts up front (event_bus signals, Clock season constants, Weather autoload stub) so all three could run fully parallel.
-
Pre-fan-out contract pattern was the key. By writing the public API surface to disk before dispatching agents, each agent's slice compiled standalone and integrated on first try. Worth repeating for any future "multi-system phase" — pay the 5-minute scaffolding cost, save the round-trip merge fixup.
-
One quick-edit fixup needed: Variant inference errors on
var old_sev := s.severity(untyped Array loop var). Same trap as the Phase 7 crop fix. Pattern: always explicit-type any:=declaration assigned from a non-typed-Array element. -
MCP runtime verified all paths. Top-bar shows "Spring 1/12", rain droplets render across screen, storm white-flash caught mid-animation, wet status flipped 0→Damp(26)→Soaked(65) with mood thought sync, cold status fired on cold_snap with -4 mood.
_is_sheltered()proxy (has floor) works for v1; Phase 13 Room BFS replaces it. -
Next: Phase 13 (Rooms, roofing, beauty, dirtiness, cleaning) is the natural follow-up — it pays the
_is_sheltered()debt and unlocks beauty/dirty mood thoughts. -
Phase 13 (Rooms + Beauty + Dirtiness + Cleaning) shipped same day. Three-agent fan-out reusing the Phase 12 contracts-first pattern (
Roomclass,World.rooms/room_at_tile/is_indoor, 4 EventBus signals pre-written by Opus before dispatch). -
DECISION: Big-room UX = bump cap to 16, banner above. Auto-roof activates for rooms ≤16 interior tiles; rooms above that emit
room_too_largewith no roof. Cabin (24 tiles) intentionally exceeds cap so the warning path is exercised at boot. Test shed (3×3 = 9 tiles) exercises the roof path. -
Agent C wiring loss + recovery. Agent C reported wiring
BeautySystem/DirtinessSystem/CleaningProvider/IndoorTintOverlayintoworld.gdbut the instantiation code never landed — only the autoload field declarations and the entity-sideregister_furniturehooks survived. Opus added the missing 4 instantiations + work-provider registration + pre-built furniture seed in a follow-up edit. Recovery time ~5 min via runtime probe. Pattern: trust but verify agent reports against actual file state, especially for "I wired this into the scene/autoload" claims. Don't repeat by asking for "show me the diff" alongside the report. -
Demo seed extended. Added
_prestamp_test_shed_for_room_detector+_spawn_complete_wall/_spawn_complete_floorhelpers — instantiates entities in completed state for a 5×5 walled shed at (34, 23). Demonstrates the auto-roof path side-by-side with the cabin's over-cap path. -
Sheltering proxy debt paid.
Pawn._is_sheltered()now readsWorld.is_indoor(tile)first, falling back to the floor-has-cell proxy for graceful degradation while RoomDetector populates. -
Phase 10 wolves' raid cooldown is set to 4800 ticks (1 in-game day). Combined with
darkness_factor ≥ 0.8trigger gate, wolves continue to spawn nightly. No tuning required this phase. -
Next: Phase 14 (Death + corpses + burial) — closes the death loop. Pairs naturally with Phase 13's
DirtinessSystem.bump()API for combat-blood spikes. -
Phase 14 (Death + corpses + burial) shipped same day. Three-agent fan-out (A: death+corpse spawn, B: graveyard+grave_slot+marker+haul, C: cremation pyre+ash+4 mood thoughts). Opus pre-wrote Corpse class with
setup()/save round-trip + 5 EventBus signals + World.corpses/grave_markers registries before dispatch. Pattern proven for the third time — this is the way. -
Bleed-out timeout shipped at design value (
BLEED_OUT_TICKS = 432000= 6 in-game hours at 20 Hz). Previous memory entry's claim of "demo value 1200" was based on a misread; the constant has been at the design value since Phase 9 status_catalog.gd landed. -
Throughput tuning surfaced as a real concern. At ULTRA speed (12×), corpses decay (DECAY_PER_TICK=0.05) hit the 100-rotted threshold before HaulingProvider's priority-3 corpse-haul scheduling could chain pawn→pickup→graveyard. Pipeline is correct; numbers need a Phase 20 pass. Workaround for testing: pause + manual job assignment, or boost corpse-haul to priority 4+.
-
recipe.gdextended withingredient2_type/countfor the cremation recipe (1 corpse + 5 wood). CraftingProvider's pickup step still only enforces ingredient1 — documented gap. Cremation pyre works as a corpse-only recipe today. -
HaulingProvider corpse path uses Node metadata (set_meta on the carrying pawn) to track the carried corpse. Agent B did this to keep Corpse class (Agent A's territory) untouched. If a proper
Pawn.carrying_corpsefield lands later, replace the metadata. -
MCP runtime verified: DEMO_PHASE14_AUTOKILL toggle force-kills first pawn at tick 50 — Bram DIED → corpse spawned → Cora's saw_corpse (-3) thought fired. Grave dig + designation paint chain verified to completion. Bleed-out + Wet status overlap firing correctly during ULTRA runs. Screenshot shows fresh corpse silhouette at cabin doorway.
-
Next: Phase 15 (Storyteller) — the world prods the player. 25-event registry, daily 6 AM roll, per-event + per-category cooldowns (both gates locked), banner/modal UI, ghost-state recovery.
-
Phase 15 (Storyteller) shipped same day. Three-agent fan-out (A: EventCatalog with all 25 events authored from design.md, B: Storyteller autoload daily roll + cooldowns + tension + ghost state, C: BannerUI + ModalUI + go-there pan). Opus pre-wrote EventDef class + 5 EventBus signals + Storyteller autoload stub before dispatch. Contracts-first pattern proven for the 4th time.
-
Code-as-data choice for events. EventCatalog is GDScript factories rather than
.tresresources. Trade-off: faster iteration in MVP (no Inspector dance, no resource UID drift), but.tresis on the table for Phase 17 if hot-reload becomes a workflow need. -
MCP runtime verified across two boots (different daily rolls per boot — RNG fresh per session):
- Boot 1:
lone_wolfTHREAT → modal "A starving wolf circles your livestock." with Prepare/Dismiss buttons + sim auto-paused. Resolve → tension bumped 27→42, sim resumed. - Boot 2:
an_old_mapLORE → top-center banner, non-blocking, 6-sec auto-dismiss.
- Boot 1:
-
Quick-edit fixup mid-flight: modal didn't auto-hide when
Storyteller.resolve_currentwas called externally (only on internal button click). Added astoryteller_event_resolvedsubscriber to the modal — one method. Phase 17 polish will sweep similar UX gaps. -
Wolf-spawn integration deferred to Phase 17 — Agent A noted
EventBus.request_wolf_spawn(count)signal not yet declared; threat events that spawn wolves currently log-stub. Pattern recorded: when a Phase-N agent surfaces a missing cross-Phase signal, declare it on EventBus in the next contracts-prep pass rather than spreading the fix across agents. -
All categories used in the 25-event corpus: nudge×4, seasonal×4, wanderer×4, threat×4, disease×3, resource×3, lore×2, milestone×1. Total cooldowns lock the per-day pool to roughly 3-6 eligible events on a typical day.
-
Next: Phase 16 (Save/load full coverage) — pays the partial-save debt accumulated since Phase 3. All entity types (pawn, item, furniture, container, corpse, wolf, plant, grave_marker), TileMap layers via
get_used_cells_by_id, Storyteller state round-trip, Bill mid-fetch states. Phase 16 is the integration phase — fewer new files, more save-seam plumbing. -
Phase 16 (Save/load full coverage) shipped same day. Three-agent fan-out (A: class_id tagging + missing to_dict/from_dict on 6 entities + tilemap helpers + beauty/dirt map serialization; B: SaveSystem v2 rewrite with per-class factory registry + clear-and-respawn apply_save + slot API; C: Autosave autoload + Save/Load TopBar buttons + LoadMenu + ResumeToast). Opus pre-wrote World.clear_all + 4 EventBus signals before dispatch. Pattern proven for the 5th time.
-
User explicitly wanted autosave + manual save/load UI — both shipped: Save (💾) + Load buttons in TopBar; Load opens slot picker; Autosave fires periodically (every 6000 ticks = ~5 in-game min) and on app pause / focus loss.
-
clear-and-respawn pattern works.
World.clear_all()wipes all entity registries + queue_frees the Nodes; SaveSystem.apply_save then iteratespayload.entitiesand dispatches to per-class factories. Verified: 113 entities saved at tick 1137, sim advanced to tick 4600 at ULTRA, load restored tick=1137 + all 3 pawns + all furniture in correct positions with 0 errors. Round-trip clean. -
Wolf target re-resolution — wolf.from_dict stores target_pawn as a name string; Agent A's note says Agent B's apply_save should re-resolve names against
World.pawnsafter all pawns are restored. Verify on next save-load cycle. -
Save version bumped to 2. v1→v2 mismatch shows a warning dialog in LoadMenu; player can continue or cancel. Future bumps follow the same pattern.
-
Known acceptable gaps: Pawn JobRunner mid-INTERACT/mid-BUILD restarts from toil 0 on reload (walk toil round-trips; multi-step interact does not). Workbench bill mid-craft fetch state isn't fully serialized. Both are tolerable — pawns just redo a few seconds of work. Document as Phase 20 tuning.
-
Three new autoloads now: Autosave (Phase 16) + Storyteller (Phase 15) + Weather (Phase 12). All registered in project.godot in dependency order (Sim/Clock first, then Weather/Storyteller/Autosave).
-
Next: Phase 17 (Touch UX completion). The biggest deferred-polish bucket — work-priority matrix UI, bills UI, alerts log, pawn detail panel, build drawer, settings menu, all the touch-first interaction layer that's been stubbed. Several Phase 14/15 effects (wanderer recruit, resource buffs, wolf-spawn signal) wire in here too.
-
Phase 17 (Touch UX completion, MVP-cut) shipped same day. Three-agent fan-out: A = PawnDetailPanel + SettingsMenu, B = BuildDrawer (with 12 new Designation tools), C = WorkPriorityMatrix + AlertsLog + Decision Layer 4 per-pawn priority refactor + EventBus.request_wolf_spawn wiring. Opus pre-wrote 6 EventBus signals + Pawn.work_priorities Dictionary stub before dispatch. Pattern proven for the 6th time.
-
TopBar now has 10 buttons: ‖ / 1× / 5× / 12× / Save / Load / Settings / Build / Work / Log[N]. + a floating ⊕ FAB at bottom-right (BuildDrawer quick-open). Crowded but functional; mobile-polish pass can group under a hamburger.
-
Decision Layer 4 refactor. Pawn.work_priorities (Dict cat→int 0..4, 0=OFF, default 3=NORMAL) is now respected. Needs categories (rest/eat/sleep) BYPASS the filter so a pawn can't accidentally starve from misconfiguration. Doctor IS in the matrix (players can opt a pawn out of doctor duty). Audit log now prefixes work decisions with
(pri=N). -
Mouse drag-paint works as-is. User specifically asked about this. Existing Selection + Designation tools read
_unhandled_inputevents for mouse motion + button-held state, so drag-painting walls/floors/designations works in the editor without further work. -
Pattern proven 6th time: "pre-write contracts to disk before fan-out". This session has been a single 1-day sprint shipping 6 phases (12 through 17) end-to-end via this pattern. Cost discipline: every phase = 3 Sonnet agents in parallel + Opus pre-write contracts + Opus integration + Opus MCP runtime verify.
-
MCP runtime verified all 4 new UI surfaces: Bram's detail panel shows Crafting=8 / Cooking=2 / Manual=0 matching seed; BuildDrawer Designate tab shows 4 tools with procedural icons; WorkPriorityMatrix shows 3 pawns × 8 categories grid with default "3" cells; AlertsLog shows 4 entries with mixed severity icons + "Spring Awakens" from the boot storyteller roll.
-
Deferred to Phase 17.5 polish pass: Per-pawn/per-job view layers, stockpile 4×4 chip grid, Bill UI, "no stockpile accepts X" / "bill blocked" emit wiring, DaySummaryCard visual.
-
Next: Phase 18 (Audio). Music + SFX + ambient + volume sliders + mute-on-suspend. Smaller scope than 17 — 1 week target. ElvGames + Ventilatore bundles include music/SFX packs we can source from.
2026-05-12
-
PC controls patch shipped (out-of-phase, for desktop testing + Steam Deck prep). New input actions: WASD/arrow pan,
=/-zoom,C/Homecenter,Tab/Shift+Tabpawn cycle,B/L/P/,panel toggles,Escapepriority stack (cancel tool → close topmost panel → deselect pawn), right-click cancel/deselect (RTS convention).Fis the newspeed_cyclebinding (handler still TODO). Touch paths untouched. Commit0b2e0fc. -
Pattern note: pawn cycling Shift+Tab. First attempt used
Input.is_key_pressed(KEY_SHIFT)to detect modifier onpawn_nextaction — this works with real keyboard but fails for MCP synthetic input (the singleton keystate isn't updated by injected events). Fix: readevent.shift_pressedon the InputEventKey directly. More reliable AND works in tests. Useevent.<modifier>_pressed, notInput.is_key_pressed(KEY_*), when reading modifiers tied to a specific key event. -
Latent pre-Phase-17 bug surfaced and fixed in same commit. WorkPriorityMatrix, AlertsLog, StorytellerModal, LoadMenu, SettingsMenu all had
MOUSE_FILTER_STOPBackdrop/Dim Controls that stayed input-active when the panel was "closed". Their open/close only toggled_root.visible/_panel.visible— neverCanvasLayer.visible(self). World mouse events (right-click deselect, left-click pawn-select) silently eaten. Each_set_visible/open/closenow togglesself.visibleso input dispatch shuts off. Why it went undetected since Phase 17: Tab-select and direct script invocation bypass_unhandled_input; the runtime verify in Phase 17 used those paths. First proper mouse-world test (this session) exposed it. -
Pattern recorded: for any CanvasLayer-based UI panel with full-screen backdrop, always toggle
self.visible(CanvasLayer) in addition to inner Control visibility, OR usemouse_filter=PASSon the backdrop. Apply when adding future modals. -
Delegation report: PC controls drafted by
gdscript-refactor(Sonnet, 2 dispatches — spec implementation + polish pass). Backdrop-bug discovery + fix done on Opus during MCP runtime verification (already in context). Headless + runtime verify all green. -
Visual sprite upgrade pass (play → fix → play loop). Three procedural draws replaced with ElvGames atlas sprites this session:
- Walls — stone-fill was at FG_Fortress (1,1), which is a tan stone floor tile (no brick texture, no cap). Swapped to (13,4) — middle column of a 3-tile-wide capped autotile, used as a non-autotile single sprite. Reads as a proper brick wall with a depth cap. Commit before context summary.
- Items on ground — five most-spawned types (stone, iron_ore, gold, wood, plank) now render from FG_Abandoned_Mines coords with a quality border + stack-count badge composited on top in
_draw(). Other types still use the original hue-hashed square fallback. Commit7274ada. - Doors — first attempt used FG_Fortress 32×32 closed-gate at (4,19); user rejected as "a door for a entrance to a castle" (commit
ac21443). Pivoted to FG_Village (3, 24), a 1-tile-wide olive-wood cabin door with U-handle extracted from the red-roofed cottage template. Commit745ab29. FG_Village.png copied intoart/tiles/.
-
Tileset survey notes (for future visual passes). FG_Fortress = ALL doors are 2-tile-wide castle gates. FG_Houses = component-style 2-wide doors (cottage but still big). FG_Village = full-house templates with 1-tile-wide cabin doors baked into the bottom row (the one we used) — good source for residential furniture, signs, windows. FG_Interior = wardrobes/dressers/wallpaper, no standalone door entities. FG_Marketplace = no doors at all.
-
MCP
execute_game_scriptquirk: scripts with 3+ statements failParse error. Workaround: pack with;or usefor x in y: a; b; c(compound for-body line). Affected this session's visual probes. -
Pattern recorded: when copying a new texture into
art/tiles/, run/mnt/d/godot/Godot_v4.6.2-stable_win64.exe --editor --headless --quitto force generation of the.importfile before any scene canpreload()it. Skipping this step yields a silent null preload at runtime. -
Delegation report this session: No delegation — handled on Opus for sprite-atlas surveys, GDScript refactors, MCP runtime verification. Pure visual / MCP-tool work; subagents would have re-read the same files repeatedly.
2026-05-15
-
Bug-triage patch shipped out-of-phase, before Phase 18 (Audio) starts. Same pattern as the 2026-05-12 PC-controls patch. Three playtest-reported bugs investigated, root-caused, fixed, and MCP-runtime-verified end-to-end. See Known bugs / triage backlog above for per-bug detail.
-
Pattern recorded — "pre-built seed masks downstream wiring gaps". Five entity types (Torch / Bed / Crate / Workbench / CremationPyre) had been missing
World.register_build_site(self)since Phase 17 landed. Nobody noticed because the cabin demo seed calls_spawn_complete_*helpers (insta-builds via direct on_build_tick loop), so no player ever painted a fresh furniture designation. Lesson: when adding a new entity type to a build-queue iterating system, always playtest the FRESH-PAINT path, not just the pre-built seed. -
Pattern recorded — "pathfinder mutation can strand walking pawns". When set_cell_walkable(false) fires, pawns already mid-walk on a path through that cell will keep stepping along the stale path and land on the now-impassable tile. AStarGrid2D requires walkable START, so the pawn idles forever. Defense-in-depth fix: Wall._complete dislodges-on-tile + Pawn._advance_walk re-checks walkability before stepping. Generalises to any future system that mutates pathfinder walkability (e.g. doors, big_rock, future fortifications).
-
Pattern recorded — "Y-sort equal-Y ambiguity". Two entities at same Y-sort root with same position.y fall back to scene-tree order, which is fragile. Always set distinct Y-positions for distinct visual layers (ground vs. above-ground). Ground-tier entities use top-of-tile anchor; above-ground entities use bottom-of-tile anchor (Wall/Bed/Torch/Workbench pattern). Pawn at mid-tile sits cleanly between.
-
Delegation report:
researcher(Haiku, 1 dispatch) mapped three bug surfaces (~600 word digest with file:line citations). All fixes + MCP runtime verification handled on Opus — fix sites were already in context from the researcher report, so re-dispatching to Sonnet would have been pure overhead. -
Job system audit + designation-gate fix shipped same day in the same bug-triage patch session. Player report: "I set some trees to be cut but no one is doing it". Root cause via
researcher(Haiku, 1 dispatch, ~900 word digest mapping all 11 WorkProviders): ChopProvider and MineProvider iteratedWorld.trees/World.rocksunconditionally —is_choppable()/is_mineable()only check progress, not designation. The&"chop"and&"mine"cases inworld.gd._on_designation_addedstashed anullsentinel and never touched the entity, so paint was purely cosmetic. Pawns were auto-chopping the nearest unfelled tree regardless of what the player painted. -
Fix: added
chop_designated: boolto Tree,mine_designated: boolto Rock + BigRock (BigRock flag covers entire 2×2 footprint viafootprint_tiles()membership check), gated both providers, wired designation paint/cancel to flip the flag, auto-designated SAMPLE_TREES / SAMPLE_ROCKS / SAMPLE_BIG_ROCKS at boot so the demo still runs end-to-end. Rimworld parity restored — pawns no longer auto-chop / auto-mine. -
Also from same audit: added reachability pre-checks (mirroring HaulingProvider) to DoctorProvider and EatProvider — they were issuing jobs to unreachable targets, then relying on JobRunner walk-cancel to clean up. The pre-check avoids the busy-spin between Decision and JobRunner.
-
Pattern recorded — "iteration-source bugs hide behind boot-seed shortcuts". The Phase 4 seed
SAMPLE_TREES/SAMPLE_ROCKSwas always being chopped/mined because providers auto-picked. Player only noticed when they painted designations and the behavior didn't change. Boot seeds that mirror "default OK" state can mask gate logic; when adding any new gate (designation, skill, capability), playtest the FRESH state, not just the seeded state. -
Other audit findings (deferred, not fixed this session): CraftingProvider has an ingredient re-scan race (ingredient may disappear between lines 73 and 91); PlantProvider only handles harvest (sow stubbed for Phase 17); RestProvider is a Phase 3 smoke-test leftover that could be deprecated. All low priority.
-
ConstructionProvider reachability gate added later same day after player report: chop designations weren't being honored. Root cause: a leftover
build_doordesignation at the test shed wall (36, 27) was unreachable (wall in the way), but ConstructionProvider (priority 6) kept offering it to every pawn every tick, and Decision picked it over chop (priority 5). JobRunner cancelled the doomed walk each tick — busy-spin starved chop. Same fix shape as Doctor/Eat: pre-checkpathfinder.find_pathbefore issuing a job; for blocking sites (walls) probe from an adjacent walkable cell. -
Door-replaces-wall replacement build added by user request. Painting
build_dooron a tile occupied by a Wall (ghost OR completed) atomically demolishes the wall in place and spawns the door ghost. Reverses Wall._complete cleanly: unstamps wall_layer, marks pathfinder walkable, recomputes rooms. Source of truth is World.build_queue so the rule covers both designation-painted walls AND pre-built seeds (cabin, test shed) which self-register via Wall._ready. Other replacement combos (floor-on-floor, wall-on-door) NOT in scope; would need separate refund/destroy rules. -
Phase 18 (Audio) shipped same day — bug-triage sprint extended into Phase 18 once the job system was solid. Scope:
- 8 curated OGG files copied into
audio/{music,sfx}/from the ElvGames bundle (Retro Farming Music 1, Cozy Melodies Pack 1, UI Pack 1, Woodcutting & Mining 1, Sword Pack 1). Two source zips (Cozy Melodies Pack 1, Retro Farming Music 1) were extracted in-place inside the bundle's Tier 1 dir. - New
autoload/audio.gdsingleton: 3 buses (Master, Music routed to Master, SFX routed to Master), lazy stream loading with per-key cache, rate-limited play_sfx (80ms cooldown to prevent chop-tick spam at ULTRA), single persistent AudioStreamPlayer for the music director, automatic music swap onClock.phase_changed(day_loop ↔ night_loop), mute onNOTIFICATION_APPLICATION_PAUSED+FOCUS_OUT. - SettingsMenu sliders (master/music/sfx) live-bound via
value_changed.connect(Audio.set_*_linear). Ambient slider intentionally unwired — no ambient bus this pass. - SFX wiring:
Tree.fell→ tree_fell,Rock.mined/BigRock.mined→ mine_tick, EventBus.pawn_took_damage → combat_hit, storyteller_event_fired → ui_confirm sting, alert_added → ui_click. - MCP runtime verified all paths: buses online, music swap day→night→day round-trips, volume sliders correctly map linear→dB (0.5 → -6.02dB, 0.0 → -80dB silent), SFX trigger on demand.
- 8 curated OGG files copied into
-
Pattern recorded — "rate-limit per-key SFX or the mixer chokes at fast sim speed". First instinct was per-chop-tick SFX from
Tree.on_chop_tick; at ULTRA (12× speed, ~12 chop ticks/sec/pawn × 3 pawns) that would saturate the audio mixer. Moved to completion-only SFX (Tree.fell, Rock.mined) plus an 80ms per-key cooldown inplay_sfx. Future ambient/tick-based SFX should reuse this throttle. -
Pattern recorded — "extract zipped asset packs into their own named folder, in place". The bundle ships some packs as zips (Cozy Melodies Pack 1, Retro Farming Music 1) and others as already-extracted folders. Each zip's top-level entry was a folder matching its name, so
unzip -qin-place created the expectedCozy Melodies Pack 1/directory alongside the .zip without flattening. Don't extract to a generic name likeaudio_extracted/— preserve the pack identity so licensing/credits stay traceable. -
Hover-inspect tooltip shipped in the same out-of-phase polish sprint as the audio + designation-gate work. New
scenes/ui/inspect_tooltip.gdCanvasLayer at z=50,PROCESS_MODE_ALWAYSso it works during pause. Priority order is: pawn → wolf → corpse → grave marker → crop (exact tile) → tree (4-tile canopy) → big rock / rock → furniture at exact tile → furniture sprite-canopy (bed +1 tile up) → item → stockpile region → floor. Iterated three times against player feedback: trees not showing (needed canopy box), beds covered by floor (needed sprite-canopy fallback because bed sprite spans 16×32), crops not showing on the exact-tile pass. -
Pattern recorded — "tall sprites need sprite-canopy fallback in pickers". Bed sits 32px tall but its
tileis only the foot row; hovering the headboard row hit the floor first because exact-tile match prefers furniture-on-this-tile. Fix: after the exact-tile pass fails, retry withtile + Vector2i(0, 1)for sprite-tall entities. Same trick will be needed for any future 2-tile-tall furniture (wardrobe, double bed, statue). -
Bed sprite rebuilt procedural after atlas misidentification. The 2026-05-12 visual pass used FG_Interior atlas coords for "beds" — those coords were actually chairs-with-cushions. User caught it as "not good and confusing where the bed is". Replaced with a procedural top-down draw: wood frame + striped blanket + pillow + foot board, 16×32, three deterministic colour variants seeded by tile coord. The cabin was 8×6 = beds slipped into the north wall; bumped to 8×7 at origin (44, 22) so the headboard row is interior floor.
-
Pattern recorded — "visually verify atlas coords during survey, not just by filename hint". FG_Interior has a band of chair sprites at the same atlas band where beds would naturally live; previous pass logged them as beds without zooming in. Future atlas surveys should ALWAYS render a
_zoom.pngwith red gridlines and visually confirm before committing to a coord constant. -
Designation tile-highlight leaked across job completion. Painting chop / mine / build left the orange/blue overlay on the tile forever, even after the job finished. Root cause: nothing called
designation_ctl.clear_cell()from entity completion handlers. Fix: addedWorld.designation_ctlfield +clear_designation_at(tile)helper, wired into completion handlers of Wall, Floor, Door, Bed, Torch, Workbench, Crate, Tree, Rock, BigRock (iterates footprint), GraveSlot. Commitf67c12c. World boot wires the controller (World.designation_ctl = designation_ctl). -
Crop sprites rebuilt with ElvGames atlas + four growable kinds. Replaced procedural stem-and-circle draw with per-kind 16×32 Sprite2D anchored bottom-of-tile (matches tree pattern). Four kinds wired: wheat, potato, corn, strawberry — first two from 4-stage sheets, last two from 5-stage sheets (we slice the first 4 cols; the 5th is a post-harvest regrow frame we ignore). Stage-to-sprite mapping: TILLED=no plant, SOWN→col 0, G1→col 1, G2→col 2, G3 + READY both→col 3 (harvest highlight is the cue, not the sprite). Boot demo plants one column per kind east of the cabin. Harvest outputs: wheat/corn → grain, potato/strawberry → vegetable. Commit
c93f889. -
Pattern recorded — ".import auto-generation via
godot --headless --import". Writing*.png.importcompanion files by hand with placeholder paths works but Godot rewrites them with proper UIDs on the first import scan. Reliable workflow: copy PNG intoart/, write minimal .import (UID will be ignored), then run/mnt/d/godot/Godot_v4.6.2-stable_win64_console.exe --headless --importonce to generate the .ctex binaries. Headless boot fails until the import scan runs. Same pattern from 2026-05-12 confirmed. -
Delegation report (whole-day 05-15 polish sprint): No delegation — all on Opus. Sprite-atlas surveys, MCP runtime verification (camera positioning, dialog dismissal, stage forcing), and the iterative play→fix→play loop kept the same files hot in context; Haiku/Sonnet handoffs would have re-read every time. The
researcher(Haiku) dispatch from earlier in the day for the job-system audit is the only delegated work. -
Workbenches rebuilt procedural after second atlas-misidentification. The 2026-05-12 atlas-sprite pass for Carpenter/Smelter/Hearth/Millstone again hit the same trap as Bed: the picked tiles read as chest-of-drawers (Carpenter, FG_Interior 24,20), candle base (Smelter, FG_Marketplace 8,30), 2-burner stove (Hearth, FG_Interior 16,32), and cushion stack (Millstone, FG_Interior 17,40). User: "the carpenter is a chest of draws? no idea what the mill is, looks like a bucket". Survey of all 7 plausible source tilesets (Interior / Marketplace / Houses / Village / Fortress / Mines / Dark Castle / Extras) found a 2×2 medieval stone fireplace at FG_Interior (12,13)..(13,14) for Hearth but 2-wide tiles don't fit the current single-column sprite system, and the other three had no clean replacement. Decision: go procedural for all four, following
CremationPyre._draw_pyreas precedent. New methods_draw_carpenter / _draw_smelter / _draw_hearth / _draw_millstonein workbench.gd;_VARIANT_SPRITEStable +_build_sprite()Sprite2D path removed;_complete()no longer touches a sprite child. Hearth is the only h=2 variant — draws stone surround + mantle + arched opening + log fire + flame teardrop extending into the tile north (Y-sort handles occlusion). Commitc97ada8. -
Pattern recorded — "atlas-misidentification trap, second occurrence — prefer procedural for named furniture". Pixel-art tile atlases pack hundreds of squat 16×16 items at low resolution; without zoomed-in inspection it's easy to mistake a furniture silhouette for what its name implies. Both Bed (2026-05-12) and the four workbenches (2026-05-15) hit this failure mode. Going forward: for furniture whose silhouette is definitional (workbench-with-tools, bed-with-pillow, millstone-as-grindstone), start with procedural draws and only swap in an atlas tile after verifying via 16× zoom that the tile actually depicts the named object. Atlas-sourced sprites are still the right call for generic decorative variation (trees, walls, floors, crops with growth stages).
-
Tree variety added via 3-season palette swap. Copied
FG_Tree_Summer.png+FG_Tree_Fall.pngfrom the Grasslands tier-1 pack intoart/sprites/(Spring was already there). 4 silhouettes × 3 palettes = 12 visual variants;tree.gdhash mixes silhouette and season independently so neighbouring tiles don't all share the same palette. Winter omitted — snowy trees would look out of place in the current biome. When a season-cycle system lands (future phase), the active texture can be swapped globally by season instead of per-tree. No growth stage / sapling system yet — bundle has no growth frames for trees, and the user's "regrow / auto-grow" ask is explicit future scope (deferred to a later phase that also covers planting designation). Commitc97ada8.
2026-05-16
-
Pre-made SW stockpiles + crates removed so items sit where they're produced until the player paints storage (matches Rimworld parity). Deleted
_spawn_sample_stockpiles()(two zones at (15,55) and (15,62)) and the two SW haul-target crates at (17,60)/(18,60). Kept the interior cabin crate at (50,23) as a starting amenity. Bills'UNTIL_Nmode counts items anywhere in world (not just stockpiles) so the Smelter's "5 stone blocks" bill still terminates. AllWorld.stockpilesconsumers iterate the list — empty-list no-op, no crashes. Commitc81e817. -
Workbench Bill Editor plan drafted for the deferred Phase 17 item ("Bill UI for workbenches"). 10-step plan saved to user-memory at
~/.claude/projects/-mnt-d-godot-rimlike/memory/plan_bill_ui.md(resilient to fresh sessions). Without this UI, every player-built workbench is functionally dead — build drawer can paint them but bills can only be set in code. Recipe.id field existence needs verification in Step 4. Starting execution 2026-05-16. -
Workbench Bill Editor shipped same day (commit
bdd4352). Tap a workbench → right-side panel with bill rows (mode toggle, target spin, pause, remove) + Add-bill popup filtered byaccepted_skill. MirrorsPawnDetailPanelexactly: layer 18, right-anchored 360 px, procedural_build_ui(), sim_tick refresh of the current-bill status only (bill list rebuilt on add/remove/select to preserve scroll). Selection chain extended inselection.gd: pawn-first then workbench, mutual-exclusion via newEventBus.workbench_selected/deselectedsignals. Closes Phase 17 deferred item. Code-level verification: headless boot clean, no runtime errors. Visual MCP verification still pending (need editor running). -
Delegation report — bill UI sprint. Steps 1, 3, 4, 6 (~5 mechanical edits across 5 files) →
quick-edit(Haiku, 1 dispatch). Step 5 (new ~432-LOC WorkbenchPanel script needing full mirror of PawnDetailPanel + 6 source files) →gdscript-refactor(Sonnet, 1 dispatch). Steps 2, 7 (selection chain + main mount, needed design judgment about mutual-exclusion and main.gd's typed-var pattern) handled on Opus. Strings table follow-up (ui.bill.until_countkey missed by Sonnet, fallback was a hardcoded literal) caught and fixed on Opus before commit. -
Pattern recorded — "main.gd typed-var pattern requires CanvasLayer.new() + set_script(), not SCRIPT.new()". First mount attempt used
WORKBENCH_PANEL_SCRIPT.new()— Godot 4's parser refused with "Cannot infer the type" becauseScript.new()returns genericObject. Switched tovar x := CanvasLayer.new(); x.set_script(SCRIPT)matching the rest of main.gd. Cheap parse error to surface via--headless --quit, but worth noting: subagents writing UI mount glue need this idiom explicitly. -
Pattern recorded — "never free a widget from within its own signal callback". Bill editor crashed when user changed mode FOREVER → UNTIL_N. Root cause: OptionButton.item_selected lambda called
_populate_bills()directly, which clears + rebuilds all bill rows — freeing the very OptionButton whose signal was still emitting. Same pattern in the Remove button. Fix:call_deferred("_populate_bills")so the rebuild runs on the next idle frame after the signal frame completes. Commit4e09dea. Applies to any UI where a child Control's signal handler mutates a parent container — always defer rebuilds. -
Pawn reskin Slice 1 shipped (commit
b4c9541). Pawns now render as AnimatedSprite2D children sourced from ElvGames Farming Characters Pack (Pack 1, chars 001-015). 9 anims per pawn: idle×4dirs + walk×4dirs + dead. Atlas pick is(absi(pawn_name.hash()) % 15) + 1— Bram=004, Cora=013, Edda=001, all visually distinct. New_atlas_for_pawn(pawn)helper is the single extension point for the future Slice 2 (armor → atlas swap when equipment+combat phase ships). Slice 1 plan archived to user-memory at~/.claude/projects/-mnt-d-godot-rimlike/memory/plan_pawn_reskin_slice1.md. 45 PNGs + .import companions copied toart/sprites/characters/. Newscenes/pawn/pawn_sprite_frames.gdbuilds the SpriteFrames from a {idle, walk, dead} atlas trio. Code-level verification clean; visual MCP verification still pending (needs editor running). -
Pattern recorded — "class_name lookups aren't reliable during cold-start parse; use preload() for sibling scripts". First attempt referenced
PawnSpriteFrames.build()in pawn.gd via the global class_name registry. Headless parse failed with "Identifier 'PawnSpriteFrames' not declared in the current scope" because pawn.gd was loaded before pawn_sprite_frames.gd registered its class_name globally. Fix:const _PAWN_SPRITE_FRAMES = preload("res://scenes/pawn/pawn_sprite_frames.gd")at the top of pawn.gd, then call_PAWN_SPRITE_FRAMES.build(atlases). Class_name is fine for public API documentation; preload is the reliable runtime resolver. -
Pattern recorded — "deferred-init data must be wired AFTER setup(), not in _ready()". First sprite mount happened in
_ready()and readpawn_name— but pawn_name is empty at _ready time (assigned later in setup()). All three pawns got atlas idx 1 (hash of empty string). Fix: moved sprite mount to_mount_sprite()called from setup() AND from_dict(), both of which assign pawn_name first. Idempotent (frees prior sprite). Same shape will recur for any future render that depends on per-instance saved state — always check whether the data the renderer reads is available at _ready vs after setup/from_dict. -
Delegation report — pawn reskin Slice 1.
quick-edit(Haiku, 1 dispatch) handled the mechanical edits across pawn.gd (facing field, save/load,_canonical_facing,_atlas_for_pawn).gdscript-refactor(Sonnet, 1 dispatch) wrote the newpawn_sprite_frames.gdhelper (~50 LOC) and wired the AnimatedSprite2D into Pawn._ready (z_index, anim switching, _facing_suffix). Opus handled the asset copy + headless --import, the two parse/runtime fixes (preload + setup-not-ready), the hash-distribution audit, and the commit. The two patterns above were caught on Opus during verification. -
BuildDrawer redesign — 2-pass iteration on Opus. First pass made the panel auto-size and anchor to bottom-center (commit
c63926a) plus added section headers in the Build tab. User rejected: panel "jumps around" between tabs. Second pass (commit88e3fa9) reverted to full-width fixed-size tray (PRESET_BOTTOM_WIDE, PANEL_HEIGHT 280 down from 600), and restructured the Build tab as side-by-side section columns (Structures / Furniture / Production) filling the wide tray horizontally instead of stacking vertically. Lesson saved to user-memory asfeedback_ui_trays.md: bottom-tray panels stay full-width fixed-size; "smaller" means shorter, not narrower; sections lay out horizontally inside the tray. -
Pattern recorded — "tray UIs: short and wide, fixed size, sections fill horizontally". Bottom-anchored UI panels in this project are framed as trays, not cards. Player wants the tray as a visual anchor; auto-resizing it per-tab feels jumpy. Future workbench / inspector / day-summary panels should follow this rule. Help-modal and DaySummaryCard (later this session) are modals, not trays — different rules apply.
-
Phase 17/18 closure sprint shipped same day (commit
bba1ce4). Three-agent fan-out (gdscript-refactor × 3) ships the deferred polish: StockpilePanel (layer 18 right-anchored; 21-chip 4-col filter grid + 5-priority segmented control + Select-all / Clear-all; mirrors WorkbenchPanel; selection chain extended to pawn → workbench → stockpile mutual-excl); DaySummaryCard (layer 19 modal auto-opens at dusk→night viaEventBus.day_ended, auto-pauses sim, weather row + stats grid + green/yellow/red tension bar; Settings opt-out persists viaGameState.settings["show_day_summary"]); atmospheric audio (rain-ambient loop on weather rain/storm with 0.5s fade-out, thunder sting on rain→storm transition, raid-warning sting onEventBus.wolf_spawned; OGGs sourced from ElvGames Cozy Melodies Pack 6 + Magic Spells Pack 6 + Sword Pack 1; reuses SFX bus so existing slider + suspend-mute inherit). Earlier worry that theno_stockpile_accepts+bill_blockedalerts needed wiring was wrong — both signals already emit end-to-end from HaulingProvider/CraftingProvider with rate-limiting and AlertsLog translators; replaced that wedge with DaySummaryCard. -
Pattern proven 7th time — contracts-first fan-out. Opus pre-wrote 3 EventBus signals (
stockpile_selected/deselected,wolf_spawned) and the WolfSpawner emit-call before dispatch. All three agents integrated on first try. -
Phase 19 (Onboarding) shipped same day (commit
59ca6ba). Decision: hint system (option a), not guided-day or tutorial-scene. Three-agent fan-out: HintSystem autoload + HintOverlay (layer 22) 7-step tour gated onEventBustriggers (welcome → pawn select → build drawer → stockpile painted → work matrix → day_ended → tour_complete), per-hint dismissal persisted asArray[String]inGameState.settings["dismissed_hints"], FIFO queue depth 3 (drop oldest), reduce-motion snap path,reset_tour()public API; HelpModal (layer 20) 5-tab static reference (Controls / Verbs / Priorities / Storyteller / Tips) opened viaEventBus.help_requested, dim-backdrop dismiss; SettingsMenu "Onboarding" section with Show-hints checkbox + Help button + Reset-hints button; tooltip pass —tooltip_textviaStrings.ton every TopBar button (with shortcut hints), BuildDrawer FAB, and every tool button (21 tools,_add_tool_btnextended with optionaltooltipparam). 67 new strings keys total. -
Pattern recorded — "generic
ui_panel_opened(panel_id)signal beats per-panel-open signals". HintSystem needs to know when BuildDrawer + WorkPriorityMatrix open (for tour gating). Instead of addingbuild_drawer_opened+work_matrix_opened, added one genericEventBus.ui_panel_opened(panel_id: StringName)that each panel emits with its own ID. New panels just call emit; HintSystem (or any future subscriber) needs one connection. Cleaner than N per-panel signals. -
Pattern proven 8th time — contracts-first fan-out. Opus pre-wrote 3 EventBus signals (
help_requested,hint_dismissed,ui_panel_opened) + 2 GameState settings defaults (show_hints,dismissed_hints) + the emit calls inBuildDrawer.open()andWorkPriorityMatrix.open()so HintSystem had clean subscribe points. One Agent A self-noted "ui_panel_opened not yet wired" but the wiring was already in place — agents sometimes report based on partial state. Trust-but-verify: I confirmed via the actual files and the runtime probe showed the chain firing correctly (welcome → dismiss → build_drawer hint). -
MCP runtime verified Phase 19 end-to-end. Welcome banner fired 2s after boot, dismissed → persisted in
dismissed_hints=["welcome"], build_drawer hint chained on nextui_panel_openedemit; HelpModal opened viahelp_requestedwith tab switching (Controls → Tips) verified. Status table indocs/implementation.mdmarked 🟡 done (pending playtest review) — Phase 19's acceptance demo ("cold tester productive in <60s") still owed; needs a real human, not MCP. -
Bug logged for Phase 20 polish — drag-paint eaten by camera (MED). When a Designate/Build/Stockpile tool is active in BuildDrawer, drag-paint should rectangle-fill, but camera_rig's drag-pan consumes the drag instead. Contradicts the 2026-05-11 memory note (that was selection drag-paint, not camera-vs-paint priority). Fix shape: Selection or Designation marks drag events handled when a paint tool is active, or camera skips pan when
Designation.active_tool != TOOL_NONE. -
Delegation report — whole-day Phase 17 closure + Phase 19 sprints. Six
gdscript-refactor(Sonnet) dispatches total across the two 3-way fan-outs. Opus handled all pre-write contracts, integration glue, MCP runtime verification, and the post-fan-out cross-check + small fix-ups (W→P keybind text in HelpModal, integration spot-checks, commits). Noquick-edit(Haiku) dispatches today — every wedge was big enough to warrant Sonnet's reasoning.
External references
- Forgejo repo: https://git.rdx4.com/megaproxy/rimlike (private)
- Owned art bundle (primary): ElvGames "Ultimate Farming RPG" Humble bundle, local at
/mnt/d/godot/assets/humble set new/. License: ElvGames terms (https://elv-games.itch.io/terms). Commercial OK with credit; no NFT/crypto/resale. - Owned art bundle (secondary): Ventilatore Fantasy Tileset Complete Bundle — https://itch.io/s/117124/the-fantasy-tileset-complete-bundle
- Mana Seed catalog (fallback if bundle gaps surface): https://seliel-the-shaper.itch.io/
- Iconic Homestead (autotile-ready wall fallback, $19.99): https://seliel-the-shaper.itch.io/iconic-homestead
- Lodestars: Rimworld (Tynan Sylvester / Ludeon Studios), Going Medieval (Foxy Voxel), Stardew Valley (ConcernedApe).
- Original brainstorm history: archived to
~/claude/archive/ideas/rimlike/after promotion. The session log there captures every decision's rationale. - Brainstorming-mode preference: see
~/.claude/projects/-home-megaproxy-claude-ideas/memory/brainstorm-ask-dont-decide.md(not directly applicable to projects but captures interaction style).