Pawn (scenes/pawn/{tscn,gd}, ~108 lines, gdscript-refactor agent):
- Node2D root (no physics — grid-snapped lerped motion); name + state labels
- _draw() paints body disc with hue derived from name.hash(), dark outline,
yellow selection ring when selected
- Clock = EventBus.sim_tick: each tick advances _step_progress by 1/10;
at 1.0 snaps tile to next waypoint, pops path. STEP_TICKS = 10 →
1 tile / 0.5 s at 1×, scales with Sim speed for free (pause/Fast/Ultra)
- _process() lerps render position between current and next tile every
render frame for smooth visual between sim ticks
- Public API: setup, walk_along_path, is_walking, set_selected,
signals walk_started/walk_completed/arrived_at_destination
Pathfinder (scenes/world/pathfinder.gd, ~110 lines, gdscript-refactor agent):
- AStarGrid2D wrapper, 80² region, DIAGONAL_MODE_NEVER (Rimworld
4-directional), Manhattan heuristic
- API: setup, set_cell_walkable (emits walkability_changed signal),
is_walkable, find_path (excludes start tile, includes end), benchmark
- find_path returns empty Array[Vector2i] for OOB endpoints, solid
destination, or disconnected areas
Selection (scenes/world/selection.gd, ~85 lines, Opus):
- Lives as a Node child of World; _unhandled_input handles mouse clicks
- Click-vs-drag discrimination: 8 px max drift + 300 ms max duration →
drags belong to the camera, only true clicks select/command
- Click on pawn → select (yellow ring); click on walkable empty tile
with a pawn selected → pathfinder.find_path + pawn.walk_along_path
World autoload (autoload/world.gd):
- Added pawn registry: register_pawn, unregister_pawn, pawn_at_tile, clear_pawns
- Untyped Array (Array[Pawn] hits Godot's class_name-not-yet-registered
timing in autoload init; duck typing fine for current consumers)
World scene (scenes/world/{tscn,gd}):
- Pathfinder + Selection nodes added as children
- _ready() wires: pathfinder.setup(MAP_SIZE_TILES), walls → pathfinder
(28 cells from 8×8 stone ring marked impassable), selection.bind(pathfinder),
spawns 3 pawns (Bram/Cora/Edda) at (20/25/30, 40), runs spike benchmark
- main.gd bootstrap line bumped Phase 1 → Phase 2
i18n: 2 new keys (pawn.state.idle, pawn.state.walking)
Spike result — AStarGrid2D path-query timing at 80²:
- 36 paths (all 4-corner pairs × 3 iterations)
- min 6 μs, avg 9.1 μs, max 18 μs
- ~55× faster than the 'sub-millisecond' target in architecture.md
MCP runtime verification:
- play_scene → 3 pawns visible with distinct hashed-hue body colours
- execute_game_script: pathfinder.find_path((20,40)→(50,40)) returns
38-step path (30 straight + 8 detour around the ring)
- bram.walk_along_path(path) → screenshot caught him mid-walk on south
side of ring with state='walking' + selection ring visible
- arrival snapshot: state='idle'
Phase 2 gotcha (documented in implementation.md): class_name registration
happens at editor scan-time, not headless-load-time. First headless run
after authoring class_name files fails until reload_project rebuilds the
global class cache. Workflow: agent writes → MCP reload_project → headless
validate. Documented for future phases.
Delegation report this phase:
- gdscript-refactor (Sonnet) #1: Pawn class — scene, script, draw logic,
movement loop, i18n keys. ~108 lines pawn.gd + 22 lines pawn.tscn.
Headless-validated by the subagent (note: validated before world.gd's
Pawn reference was added).
- gdscript-refactor (Sonnet) #2: Pathfinder class — AStarGrid2D wrapper,
4-dir Manhattan, benchmark utility. ~110 lines pathfinder.gd. Headless-
validated by the subagent.
- Opus: Selection module + World autoload registry + scene integration
(world.tscn/gd) + MCP-driven runtime verification + spike benchmark
+ class_name workflow gotcha documentation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
World scene (scenes/world/world.{tscn,gd}):
- 6 TileMapLayer nodes per architecture.md split: Terrain (0), Floor (1),
Wall (2), Designation (3), Roof (4, hidden), Fog (5, hidden).
- Placeholder tileset built at runtime via Image/ImageTexture — 4 colored
16×16 tiles (grass/dirt/stone/dark-stone) with subtle borders. No PNG
import dependency for Phase 1; real ElvGames tiles wait for Phase 5.
- Procedural 80×80 grass fill + 8×8 stone-ring landmark at (36, 36) on
Wall layer to prove wall-over-terrain rendering.
- Calls camera_rig.set_world_bounds() once map dimensions known.
- ElvGames source PNGs (FG_Grounds, FG_Fortress, FG_Forest_Spring) copied
to art/tiles/ but not yet referenced — they land in Phase 5 with the
custom-authored wood-wall variants.
Camera rig (scenes/world/camera_rig.{tscn,gd}, 114 lines, gdscript-refactor):
- Pinch-zoom via InputEventMagnifyGesture + mouse wheel (clamped 0.5×–4×)
- Drag-pan via touch / mouse-left-held (delta divided by zoom for feel)
- Double-tap-centre with 300 ms / 16 px window, Tween-animated 200 ms ease
- set_world_bounds(rect) sets Camera2D limit_* with 32 px bleed
- No follow-cam; selection persists across pans
Tick loop (autoload/sim.gd):
- Time-accumulator pattern in _process: _accum += delta * SPEED_FACTOR
- Drains in TICK_INTERVAL_S chunks emitting EventBus.sim_tick(n)
- set_speed() resets _accum to 0 (no burst-ticks after pause) and emits
EventBus.speed_changed(int). Boot default = NORMAL.
- Audit.log on every speed transition for runtime diagnostics.
- Early-return guard against redundant set_speed calls.
EventBus (autoload/event_bus.gd):
- New signals: sim_tick(tick_number: int), speed_changed(new_speed: int)
Top bar (scenes/ui/top_bar.{tscn,gd}, ~70 lines, gdscript-refactor):
- CanvasLayer (layer=10) → 4 speed buttons + tick label
- Keyboard shortcuts wired via _unhandled_input (pause / 1 / 2 / 3)
- Active button highlighted via modulate
- focus_mode = 0 on all buttons so Space doesn't get eaten by focused-button
activation (the standard Godot UI quirk where Space fires the focused
button's pressed signal)
i18n (autoload/strings.gd):
- 5 new keys: speed.pause/normal/fast/ultra, hud.tick (template with {n})
Main bootstrap (scenes/main/main.{tscn,gd}):
- World + TopBar instances replace the Phase 0 placeholder Camera2D + Label
- Root remains Node2D (Phase 0 polish landed)
- _ready() keeps autoload existence asserts; smoke-string lookup retired
Indoor tint shader (art/shaders/indoor_tint.gdshader):
- Stub: tint_strength = 0 pass-through. Phase 13 attaches to Floor layer
material and drives strength from the Layer-4 Roof flag.
Acceptance: MCP-verified via play_scene + get_game_screenshot. 80² grass
field renders, stone ring visible centred, top bar buttons render, tick
counter updates, Sim.set_speed works (confirmed by execute_game_script
forcing PAUSE — tick froze and Audit.log emitted the transition line).
Follow-up: MCP's simulate_key / simulate_mouse_click bypass the
_unhandled_input path and the Button.pressed signal — events don't reach
the handler. Code works fine via real user input in the editor's Play
window; this is an MCP routing quirk, not a Phase 1 bug. Documented as
a known limitation when scripting input tests.
Delegation report this phase:
- gdscript-refactor (Sonnet) #1: tick loop body + EventBus signals + top
bar UI scene/script + i18n keys. ~3 file mods + 2 new files. Headless-
validated by the subagent.
- gdscript-refactor (Sonnet) #2: camera rig scene + script. 2 new files,
114 lines GDScript. Headless-validated by the subagent.
- Opus: world scene + procedural tileset + map fill + integration into
main.tscn + MCP-driven runtime verification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Researcher (Haiku) scanned all 6 Ventilatore packs (Premium, Castles
and Fortresses, Medieval Interiors, Desert Oasis, Snow Adventures,
Turning of the Seasons). The bundle is character + terrain + decoration
only — no animal/creature sprites at all except player + slimes.
Wolf options now narrowed to: commission, CC0 source, or recolor-a-dog
placeholder until Phase 10. Ventilatore-search sub-option closed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wood walls (early game) custom-authored on top of FG_Houses warm-brown
timber palette to preserve the Stardew-cabin warmth that's the project's
aesthetic anchor. ~½ day of pixel art for corner/T/cap/cross variants.
Stone walls (upgrade material) imported from FG_Fortress autotile-solvable
as-is. Both materials plug into the same WallMaterial enum / construction
pipeline. Phase 5 estimate bumped from 2-3 wks to 2.5-3.5 wks.
Phase 1 wall-rendering test now specified: use FG_Fortress as the
drop-in test material; wood walls land in Phase 5 alongside the
authoring task.
Iconic Homestead $19.99 fallback formally not needed.
memory.md decisions table now includes the wall locks; the original
3-option open question collapsed to a back-reference. art.md got a
new 'Wall-material decision' section replacing the options block.
Wolf-sprite question still open; Ventilatore search dispatched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Project scaffold:
- project.godot at repo root, GL Compatibility renderer (max mobile reach),
pixel-snap on, texture filter nearest, sensor_landscape orientation
- 7 autoloads: World, Sim, GameState, EventBus, Strings, Audit, SaveSystem
- scenes/main/main.{tscn,gd} smoke-test scene with autoload assertions
- Folder layout matches tavernkeep idiom: autoload/ at root, scripts
co-located with scenes/ (not the scripts/autoloads/ mirror originally
sketched in implementation.md)
- Input map: pause, speed_cycle, speed_normal/fast/ultra, confirm, cancel.
Mobile gestures (pinch/drag/long-press) handled at script level via
Godot's InputEventScreenTouch/Drag/MagnifyGesture.
- SaveSystem skeleton: SAVE_VERSION=1, JSON to user://save_slot.json,
version-mismatch warning. Phase 3 expands to real entity state.
- icon.svg placeholder (cabin silhouette on dark green field)
- README.md points at memory.md / implementation.md / docs/
Headless verification: 'godot --headless --path . --quit' exits 0,
'[main] Phase 0 smoke test online.' prints, no errors. Editor-side
green-dot check still pending — needs human launch of editor.
Asset audit (researcher Haiku, 2026-05-10):
- FG_Houses.png NOT autotile-solvable — pre-built decorative house
compositions, 4 distinct roof palettes, no modular wall family.
~½–1 day per material to author terrain bits on top.
- FG_Fortress.png IS autotile-solvable — ~20–30 modular tan-stone
pieces. Wang-style Godot 4 terrain works with minimal extra art.
Iconic Homestead $19.99 fallback not needed.
- No wolf sprite anywhere in the bundle. EvoMonster packs all
cute/fantasy. Need commission, CC0 source, or Ventilatore check.
- Retro Graveyard 16x16 [Kingdom Explorer] confirmed in Tier 3 with
full graveyard suite — direct use in Phase 14.
New open questions surfaced in memory.md:
- Player-built wall material strategy (3 options laid out)
- Wolf sprite acquisition path (Phase 10 blocker)
Project move:
- Repo physical location moved from ~/claude/projects/rimlike to
/mnt/d/godot/rimlike (D: drive, fast for Windows-side editor).
- Symlink at the original WSL path preserves the home-CLAUDE.md
layout convention. Mirrors tavernkeep's pattern.
- Set core.filemode=false to silence DrvFs's everything-is-0777
false-positive on git diff.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21 phases from clean-slate to MVP, dependency-ordered with each
phase ending in a runnable demo state. Includes:
- Pre-implementation audit (the 75-min asset checks from memory.md)
- Phases 0–20 with checklist + acceptance criteria + spec-doc refs
- Two DECIDE points (Phase 13 big-room UX, Phase 19 onboarding)
- Out-of-scope list (procgen, biomes, butchering, surgery, etc.)
- Scope-cut levers ranked by gameplay-cost-per-week-saved
- De-risking spikes per phase
- Wired into memory.md index + session log; current Status =
Phase 0 (gated by the 75-min audit)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves the rimlike docs audit. Decisions made this session:
- Map: 40² → 80² for MVP slice; architecture sized to ~120² ceiling.
Pawn count unchanged (3 start / 6 cap) — 'split-the-difference'
sizing rather than frontier-feel scale.
- World-view camera (locked): pinch + drag-pan + double-tap-centre.
Storyteller alerts include 'Go there' tap. No minimap, no
follow-cam in MVP. New ui.md section captures this.
- Storyteller cooldowns: per-event AND per-category — both gates
must pass. Resolves design.md/architecture.md disagreement.
- MAX_STACKS_PER_THOUGHT = 5 (was named-but-unset).
- Hauling no-destination fallback: drop after 3 retry passes,
surface a passive 'No stockpile accepts X' alert.
- Container all-neighbors-blocked: hold then drop after ~5 sim s
to avoid deadlock.
- Auto-roof big-room UX: emits room_too_large signal when BFS hits
the ≤8-cell cap; UI surfaces a 'split with an interior wall'
banner. Threshold + exact wording added to memory.md TODOs.
Doc rot cleaned in design.md and architecture.md: removed the stale
'8 work categories' intermediate sections (canonical 9-list lives
later in each file). Updated architecture.md perf claims for the new
map size.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promoted from ~/claude/ideas/rimlike after a single multi-hour brainstorm
session. memory.md distilled from plan.md; companion design / architecture /
ui / art docs preserved under docs/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>